package com.baijiayun.live.ui

import android.Manifest
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.view.*
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.core.widget.TextViewCompat
import androidx.lifecycle.Observer
import com.baijiayun.live.ui.activity.LiveRoomBaseActivity
import com.baijiayun.live.ui.activity.LiveRoomRouterListener
import com.baijiayun.live.ui.base.*
import com.baijiayun.live.ui.base.BasePresenter
import com.baijiayun.live.ui.base.BaseView
import com.baijiayun.live.ui.base.getViewModel
import com.baijiayun.live.ui.chat.MessageSendFragment
import com.baijiayun.live.ui.chat.MessageSendPresenter
import com.baijiayun.live.ui.error.ErrorFragmentModel
import com.baijiayun.live.ui.error.ErrorPadFragment
import com.baijiayun.live.ui.interactivepanel.InteractiveFragment
import com.baijiayun.live.ui.mainvideopanel.MainVideoFragment
import com.baijiayun.live.ui.menu.rightmenu.RightMenuContract
import com.baijiayun.live.ui.ppt.quickswitchppt.QuickSwitchPPTFragment
import com.baijiayun.live.ui.ppt.quickswitchppt.SwitchPPTFragmentPresenter
import com.baijiayun.live.ui.pptpanel.PPTFragment
import com.baijiayun.live.ui.pptpanel.pptmanage.PPTManageWindow
import com.baijiayun.live.ui.setting.SettingDialogFragment
import com.baijiayun.live.ui.share.LPShareDialog
import com.baijiayun.live.ui.speakerlist.item.Switchable
import com.baijiayun.live.ui.speakerlist.item.SwitchableStatus
import com.baijiayun.live.ui.speakpanel.SpeakFragment
import com.baijiayun.live.ui.toolbox.announcement.AnnouncementFragment
import com.baijiayun.live.ui.toolbox.announcement.AnnouncementPresenter
import com.baijiayun.live.ui.toolbox.custom_webpage.CustomWebPageDialogFragment
import com.baijiayun.live.ui.toolbox.evaluation.EvaDialogFragment
import com.baijiayun.live.ui.toolbox.evaluation.EvaDialogPresenter
import com.baijiayun.live.ui.toolbox.lottery.LotteryAnimFragment
import com.baijiayun.live.ui.toolbox.lottery.LotteryFragment
import com.baijiayun.live.ui.toolbox.questionanswer.QAInteractiveFragment
import com.baijiayun.live.ui.toolbox.quiz.QuizDialogFragment
import com.baijiayun.live.ui.toolbox.quiz.QuizDialogPresenter
import com.baijiayun.live.ui.toolbox.redpacket.RedPacketFragment
import com.baijiayun.live.ui.toolbox.redpacket.RedPacketPresenter
import com.baijiayun.live.ui.toolbox.timer.TimerFragment
import com.baijiayun.live.ui.toolbox.timer.TimerPresenter
import com.baijiayun.live.ui.toolbox.timer.TimerShowyFragment
import com.baijiayun.live.ui.topmenu.TopMenuFragment
import com.baijiayun.live.ui.utils.FileUtil
import com.baijiayun.live.ui.utils.JsonObjectUtil
import com.baijiayun.live.ui.utils.QueryPlus
import com.baijiayun.live.ui.viewsupport.dialog.SimpleTextDialog
import com.baijiayun.livecore.LiveSDK
import com.baijiayun.livecore.context.LPConstants
import com.baijiayun.livecore.context.LPError
import com.baijiayun.livecore.context.LiveRoom
import com.baijiayun.livecore.listener.LPLaunchListener
import com.baijiayun.livecore.listener.OnPhoneRollCallListener
import com.baijiayun.livecore.models.*
import com.baijiayun.livecore.models.launch.LPEnterRoomNative
import com.baijiayun.livecore.models.roomresponse.LPResRoomReloadModel
import com.baijiayun.livecore.utils.*
import com.baijiayun.livecore.wrapper.LPRecorder
import com.baijiayun.liveuibase.base.*
import com.baijiayun.liveuibase.loading.LoadingWindow
import com.baijiayun.liveuibase.loading.OnLoadingCompleteListener
import com.baijiayun.liveuibase.skin.SkinInflateFactory
import com.baijiayun.liveuibase.toolbox.answerer.AdminAnswererWindow
import com.baijiayun.liveuibase.toolbox.answerer.AnswererWindow
import com.baijiayun.liveuibase.toolbox.bonuspoints.BonusPointsWindow
import com.baijiayun.liveuibase.toolbox.redpacket.RedPacketPublishWindow
import com.baijiayun.liveuibase.toolbox.responder.ResponderRobButton
import com.baijiayun.liveuibase.toolbox.responder.ResponderWindow
import com.baijiayun.liveuibase.toolbox.responder.model.ResponderRecordModel
import com.baijiayun.liveuibase.toolbox.rollcall.AdminRollCallDialogFragment
import com.baijiayun.liveuibase.toolbox.rollcall.RollCallDialogFragment
import com.baijiayun.liveuibase.toolbox.rollcall.RollCallDialogPresenter
import com.baijiayun.liveuibase.toolbox.rollcall.RollCallStatus
import com.baijiayun.liveuibase.toolbox.screenshare.ScreenShareHelper
import com.baijiayun.liveuibase.utils.DisplayUtils
import com.baijiayun.liveuibase.utils.DisplayUtils.isPad
import com.baijiayun.liveuibase.utils.ThemeDataUtil
import com.baijiayun.liveuibase.utils.showBonusPointsTab
import com.baijiayun.liveuibase.widgets.AwardView
import com.baijiayun.liveuibase.widgets.dialog.QuestionDialogFragment
import com.baijiayun.liveuibase.widgets.dialog.ThemeMaterialDialogBuilder
import com.baijiayun.utils.LogUtil
import com.google.gson.JsonObject
import com.tencent.mmkv.MMKV
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.bjy_activity_live_room_pad.*
import kotlinx.coroutines.*
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.math.roundToInt

/**
 * 标准三分屏界面
 */
open class LiveRoomTripleActivity : LiveRoomBaseActivity(), RouterListener {
    private val logTag = "LiveRoomTripleActivity"
    protected lateinit var routerViewModel: RouterViewModel
    private lateinit var liveRoomViewModel: LiveRoomViewModel
    private lateinit var oldBridge: OldLiveRoomRouterListenerBridge
    private var showyTimerPresenter: TimerPresenter? = null
    private var quickSwitchPPTPresenter: SwitchPPTFragmentPresenter? = null
    private var rollCallDialogFragment: RollCallDialogFragment? = null
    private var rollCallDialogPresenter: RollCallDialogPresenter? = null
    private var adminRollCallDlg: AdminRollCallDialogFragment? = null
    private var responderWindow: ResponderWindow? = null
    private var responderPrepareView: View? = null
    private var responderRobButton: ResponderRobButton? = null
    private var quizFragment: QuizDialogFragment? = null
    private var quizPresenter: QuizDialogPresenter? = null
    private var announcementFragment: AnnouncementFragment? = null
    private var qaInteractiveFragment: QAInteractiveFragment? = null
    private var redPacketFragment: RedPacketFragment? = null
    private var redPacketPresenter: RedPacketPresenter? = null
    private var lotteryFragment: LotteryFragment? = null
    private var lotteryAnimFragment: LotteryAnimFragment? = null
    private var timerFragment: TimerFragment? = null
    private var timerShowyFragment: TimerShowyFragment? = null
    private var pptManageWindow: PPTManageWindow? = null
    private var evaDialogFragment: EvaDialogFragment? = null
    private var mobileNetworkDialogShown = false
    private var minVolume = 0
    private var disposeOfTeacherAbsent: Disposable? = null
    private var disposeOfLoginConflict: Disposable? = null
    private var disposeOfMarquee: Disposable? = null
    private var disposeOfMarqueeDouble: Disposable? = null
    private var disposeOfMainScreenNotice: Disposable? = null
    private var marqueeAnimator: ObjectAnimator? = null
    private var marqueeAnimatorDouble: ObjectAnimator? = null
    private val job = Job()
    private var marqueeBlinkTextView: TextView? = null
    private var marqueeBlinkDoubleTextView: TextView? = null
    private lateinit var skinInflateFactory: SkinInflateFactory
    private var answererWindow: BaseWindow? = null
    private var adminAnswererWindow: BaseWindow? = null
    private var redPacketPublishWindow: BaseWindow? = null
    private var bonusPointsWindow: BaseWindow? = null
    protected var toolboxLayer: BaseLayer? = null
    protected var pptContainerViewGroup: ViewGroup? = null
    private var loadingWindow: LoadingWindow? = null
    private var onLoadingCompleteListener: OnLoadingCompleteListener? = null
    protected val REQUEST_CODE_PERMISSION_CAMERA_TEACHER = 0

    private var mainScreenNoticeAnimator: ObjectAnimator? = null
    private var mainScreenNoticeContainer: FrameLayout? = null
    private var screenShareHelper: ScreenShareHelper? = null

    private var settingFragment: SettingDialogFragment? = null

    // 双师班型大小班切换需要释放资源
    private val marqueeObserver = Observer<Pair<Boolean, LPEnterRoomNative.LPHorseLamp>> {
        it?.let {
            if (it.first) {
                // 协程需要Destroy()取消Job
                val scope = CoroutineScope(job)
                scope.launch(Dispatchers.Main) {
                    // s -> ms
                    delay(it.second.displayRollDuration * 1000L)
                    showMarqueeRoll(it.second)
                }
            }
        }
    }

    /**
     * 问答计时器观测
     */
    private val timerObserver by lazy {
        Observer<Pair<Boolean, LPBJTimerModel>> {
            it?.let {
                if (it.first && it.second.action != TimerPresenter.stop_timer) {
                    if (routerListener.liveRoom.currentUser.type != LPConstants.LPUserType.Teacher || it.second.action != null)
                        showTimerShowy(it.second)
                    else
                        showTimer(it.second)
                } else closeTimer()
            }
        }
    }
    private val answerObserver by lazy {
        Observer<LPAnswerModel> {
            it?.let {
                if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Student) {
                    initStudentAnswerer(it)
                } else {
                    initTeacherAnswerer(it)
                }
            }
        }
    }

    private val answerEndObserver by lazy {
        Observer<LPComponentDestroyModel> {
            if (it == null) {
                destroyWindow(adminAnswererWindow)
                adminAnswererWindow = null
                destroyWindow(answererWindow)
                answererWindow = null
                destroyWindow(responderWindow)
                responderWindow = null
                return@Observer
            }
            if (LPConstants.ComponentType.Responder.componentType == it.value.component) {
                destroyWindow(responderWindow)
                responderWindow = null
            } else if (LPConstants.ComponentType.Answerer.componentType == it.value.component) {
                destroyWindow(adminAnswererWindow)
                adminAnswererWindow = null
                destroyWindow(answererWindow)
                answererWindow = null
            }
        }
    }

    private val showRollCallObserver by lazy {
        Observer<Pair<Int, OnPhoneRollCallListener.RollCall?>> {
            it?.let {
                if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Student) {
                    showRollCallDlg(it.first, it.second)
                    //小班老师，没有工具箱，不反应也不显示同步状态
                } else if (routerViewModel.liveRoom.isTeacherOrAssistant) {
                    if (it.first == -1) {
                        if (routerViewModel.rollCallStatus == RollCallStatus.None) {
                            lpRoomRollCallResultModel =
                                routerViewModel.liveRoom.toolBoxVM.cacheRollCallResult
                            if (lpRoomRollCallResultModel == null) {
                                routerViewModel.rollCallStatus = RollCallStatus.Start
                                showAdminRollCallDlg(duration = rollCallTime)
                            } else {
                                routerViewModel.rollCallStatus = RollCallStatus.End
                                showAdminRollCallDlg(
                                    duration = rollCallTime,
                                    lpRoomRollCallResultModel = lpRoomRollCallResultModel
                                )
                            }
                        } else {
                            if (lpRoomRollCallResultModel != null) {
                                showAdminRollCallDlg(
                                    duration = rollCallTime,
                                    lpRoomRollCallResultModel = lpRoomRollCallResultModel
                                )
                            } else {
                                showAdminRollCallDlg(duration = rollCallTime)
                            }
                        }
                    } else {
                        if (routerViewModel.liveRoom.roomInfo.teacherDisplaySignInTriggerByAssistant != 1
                            && routerViewModel.liveRoom.speakQueueVM.isPresenterUser(routerViewModel.liveRoom.currentUser)
                            && adminRollCallDlg == null
                        ) {
                            LPRxUtils.dispose(rollcallCdTimer)
                            routerViewModel.rollCallStatus = RollCallStatus.Going
                            rollCallTime = it.first
                            startRollCallTimer(true)
                        } else {
                            LPRxUtils.dispose(rollcallCdTimer)
                            routerViewModel.rollCallStatus = RollCallStatus.Going
                            rollCallTime = it.first
                            showAdminRollCallDlg(duration = it.first)
                            startRollCallTimer(true)
                        }
                    }
                }
            }
        }
    }
    private val dismissRollCallObserver by lazy {
        Observer<Boolean> {
            it?.let {
                if (it) {
                    //老师主动关闭
                    if (routerViewModel.liveRoom.isTeacherOrAssistant) {
                        dismissAdminRollCallDlg()
                    }
                } else {
                    // 学生直接关闭点名
                    if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Student) {
                        dismissRollCallDlg()
                    }
                }
            }
        }
    }
    private val rollCallResultObserver by lazy {
        Observer<LPRoomRollCallResultModel> {
            it?.let {
                if (routerViewModel.liveRoom.roomInfo.teacherDisplaySignInTriggerByAssistant != 1
                    && routerViewModel.liveRoom.speakQueueVM.isPresenterUser(routerViewModel.liveRoom.currentUser)
                    && adminRollCallDlg == null
                ) {
                    routerViewModel.rollCallStatus = RollCallStatus.CoolDown
                    rollCallTime = ROLL_CALL_CD_TIME
                    startRollCallTimer()
                    this.lpRoomRollCallResultModel = it
                    dismissAdminRollCallDlg()
                } else {
                    routerViewModel.rollCallStatus = RollCallStatus.CoolDown
                    rollCallTime = ROLL_CALL_CD_TIME
                    startRollCallTimer()
                    this.lpRoomRollCallResultModel = it
                    showAdminRollCallDlg(duration = rollCallTime, lpRoomRollCallResultModel = it)
                }
            }
        }
    }

    private val showResponderObserver by lazy {
        Observer<Boolean> {
            it?.let {
                showResponderWindow()
            }
        }
    }

    private val startResponderObserver by lazy {
        Observer<LPAnswerRacerStartModel> {
            LPRxUtils.dispose(responderButtonDelayDisposable)
            if (routerViewModel.liveRoom.isTeacherOrAssistant) {
                showResponderWindow()
                responderWindow!!.changeStatus(ResponderWindow.ResponderStatus.PUBLISHING, "")
            } else if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Student) {
                if (it.prepareTime > 0) {
                    showResponderPrepare(it.prepareTime)
                } else {
                    showResponderButton()
                }
            }
            responderWindow?.changeStatus(ResponderWindow.ResponderStatus.PUBLISHING, "")
        }
    }

    private val endResponderObserver by lazy {
        Observer<LPAnswerRacerEndModel> {
            if (it.isRevoke) {
                cancelResponder()
                toolboxLayer?.removeView(responderRobButton)
                showToastMessage(R.string.base_responder_cancel)
            } else {
                if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Student) {
                    if (it.winner != null) {
                        if (it.winner == routerViewModel.liveRoom.currentUser) {
                            responderRobButton!!.changeRobButtonStatus(ResponderRobButton.RobButtonState.ROBED)
                        } else if (it.winner.group == routerViewModel.liveRoom.currentUser.group) {
                            responderRobButton!!.changeRobButtonStatus(ResponderRobButton.RobButtonState.ROB_FAIL)
                        }
                    } else {
                        showToastMessage(R.string.base_responder_nobody_rob_student)
                    }
                    responderButtonDelayDisposable = Observable.just("").delay(3, TimeUnit.SECONDS)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            toolboxLayer?.removeView(responderRobButton)
                        }
                    cancelResponder()
                }
                if (it.winner != null) {
                    if (it.winner.group != routerViewModel.liveRoom.currentUser.group
                        && routerViewModel.liveRoom.onlineUserVM.enableMyGroupUsersPublish()
                    ) {
                        showToastMessage(R.string.base_responder_nobody_rob_student)
                        return@Observer
                    }
                    var awardText = CommonUtils.getEncodePhoneNumber(it.winner.name)
                    if (awardText.length > 3) {
                        awardText = awardText.substring(0, 3) + "..."
                    }
                    awardText = "\"" + awardText + "\"" + getString(R.string.base_responder_success)
                    showAwardAnimation(Pair(awardText, LPInteractionAwardModel()))
                }
            }
        }
    }

    private val toastObserver by lazy {
        Observer<String> { it?.let { showMessage(it) } }
    }
    private val reportObserver by lazy {
        Observer<Unit> {
            routerViewModel.liveRoom.toolBoxVM.requestAttentionReport(
                CommonUtils.isFocus(this),
                routerViewModel.liveRoom.currentUser as LPUserModel
            )
        }
    }
    private val speakStatusObserver by lazy {
        Observer<Int> {
            it?.let {
                when (it) {
                    //上台后发送user_update
                    RightMenuContract.STUDENT_SPEAK_APPLY_SPEAKING -> {
                        //不在前台liveData事件不响应直接发送media_publish
                        if (!CommonUtils.isAppForeground(this)) {
                            routerViewModel.liveRoom.mediaVM.sendMediaPublish(true)
                        }
                        routerViewModel.liveRoom.onlineUserVM.updateMediaState()
                    }
                }
            }
        }
    }

    /**
     * 观测加入直播间是否加入成功
     * 通过LoadingWidow.checkDevices() 进行加入直播间操作，检测用户状态，是否被踢等 如果失败则进入这里
     * 具体的错误提示Fragment 为
     * {@Link ErrorPadFragment}
     */
    private val showErrorObserver by lazy {
        Observer<LPError> {
            when (it?.code) {
                LPError.CODE_ERROR_LOGIN_KICK_OUT.toLong(), LPError.CODE_ERROR_LOGOUT_CLASS_ROOM_CLOSE.toLong() -> showKickOutDlg(
                    it
                ) //被踢出房间后的登录
                LPError.CODE_ERROR_LOGIN_AUDITION.toLong() -> showAuditionEndDlg(it) // 试听结束
                else -> {
                    loadingContainer.removeView(loadingWindow?.view)
                    if (errorFragment.isAdded || findFragment(loadingContainer.id) is ErrorPadFragment) return@Observer
                    showErrorDlg(it)
                }
            }
        }
    }

    /**
     * 观测是否可以进入直播页面
     */
    private val navigateToMainObserver by lazy {
        Observer<Boolean> {
            if (it == true) {
                //
                navigateToMain()
                //
                observeSuccess()
            }
        }
    }

    private var isSelfEnd = false
    private var disposableOfPlaybackTrans: Disposable? = null
    private val classEndObserver by lazy {
        Observer<Unit> {
            if (!isSelfEnd) return@Observer
            isSelfEnd = false
            disposableOfPlaybackTrans = routerViewModel.liveRoom.requestPlaybackProcessStatus()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    //存在一段录制且未开始生成回放
                    if (it.status == 1) {
                        if (routerViewModel.liveRoom.isLongTerm) {
                            if (routerViewModel.liveRoom.partnerConfig.generatePlaybackAfterClassForLongTerm) {
                                routerViewModel.liveRoom.requestCloudRecordStartProcessing()
                                finish()
                            } else {
                                if (!routerViewModel.liveRoom.partnerConfig.useSecretCloudRecord) {
                                    showGeneratePlaybackDialog(true)
                                }
                            }
                        } else {
                            if (routerViewModel.liveRoom.partnerConfig.generatePlaybackAfterClass) {
                                routerViewModel.liveRoom.requestCloudRecordStartProcessing()
                                finish()
                            } else {
                                if (!routerViewModel.liveRoom.partnerConfig.useSecretCloudRecord) {
                                    showGeneratePlaybackDialog(false)
                                }
                            }
                        }
                    } else {
                        finish()
                    }
                }
        }
    }

    private val timeOutObserver by lazy {
        Observer<Pair<String, Boolean>> {
            it?.run {
                if (second) {
                    val timeDispose = Observable.timer(30, TimeUnit.SECONDS)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            //取消邀请
                            routerViewModel.liveRoom.speakQueueVM.sendSpeakInviteReq(first, false)
                        }
                    timeOutDisposes[first] = timeDispose
                } else {
                    LPRxUtils.dispose(timeOutDisposes[first])
                    timeOutDisposes.remove(first)
                }
            }
        }
    }
    private val roomLayoutSwitchObserver by lazy {
        Observer<Boolean> {
            switchRoomLayout()
        }
    }
    private val switch2FullScreenObserver by lazy {
        Observer<Pair<Boolean, Switchable?>> {
            it?.run {
                if (it.first) {
                    (mainScreenNoticeContainer?.layoutParams as? FrameLayout.LayoutParams)?.topMargin =
                        0
                    removeViewFromParent(pptContainer)
                    fullScreenContainer.addView(
                        pptContainer,
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT
                    )
                } else {
                    removeViewFromParent(pptContainer)
                    pptContainerViewGroup?.addView(
                        pptContainer,
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT
                    )
                    it.second?.run {
                        when (switchableStatus) {
                            SwitchableStatus.MaxScreen -> switchToMaxScreen()
                            SwitchableStatus.MainVideo -> switchToMainScreen()
                            else -> switchToSpeakList()
                        }
                    }
                }
            }
        }
    }
    private val syncPPTVideoObserver by lazy {
        Observer<Boolean> {
            it?.let {
                if (::liveRoomViewModel.isInitialized) {
                    liveRoomViewModel.registerSyncPPTVideo()
                }
            }
        }
    }
    private val timeOutDisposes = HashMap<String, Disposable>()

    //试听码dialog提示
    private var mAuditionEndDialog: SimpleTextDialog? = null
    private val loadingContainer by lazy {
        findViewById<FrameLayout>(R.id.activity_live_room_pad_room_loading_container)
    }
    private val fullScreenContainer by lazy {
        findViewById<FrameLayout>(R.id.activity_live_room_pad_room_full_screen_container)
    }
    protected val pptContainer by lazy {
        FrameLayout(this)
    }
    private val errorContainer by lazy {
        findViewById<FrameLayout>(R.id.activity_live_room_pad_room_error_container)
    }
    private val errorFragment by lazy {
        ErrorPadFragment()
    }
    private val messageSentFragment by lazy {
        MessageSendFragment.newInstance()
    }

    private var messageSendPresenter: MessageSendPresenter? = null

    private val customWebPageDialogFragment by lazy {
        CustomWebPageDialogFragment()
    }

    private val REQUEST_CODE_PERMISSION_WRITE = 21

    private val disposables = CompositeDisposable()

    override fun onCreate(savedInstanceState: Bundle?) {
        MMKV.initialize(this)
        initFullScreen()
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
        skinInflateFactory = SkinInflateFactory()
        layoutInflater.factory = skinInflateFactory
        super.onCreate(savedInstanceState)
        setContentView(getContentResId())
        LiveSDK.ENABLE_AUTO_LOAD_AWARD_DRAWABLE = true
        changeLayoutParams()
        hideSysUIComponent()
        LiveSDK.checkTeacherUnique = true
        enterRoom()
    }

    open fun changeLayoutParams() {
        /*if (!isPad(this)) {
            LogUtil.d(logTag,"ScreentApectRatio====>>> $${getScreentApectRatio(this)}")
            if (!isAspectRatioNormal(this)) {
                val layoutParams =
                    findViewById<View>(R.id.activity_live_room_pad_background).layoutParams
                if (layoutParams is ConstraintLayout.LayoutParams) {
                    if (isAspectRatioSmall(this)) {
                        layoutParams.dimensionRatio = "H,16:9"
                    } else {
                        layoutParams.dimensionRatio = "W,16:9"
                    }
                }
            }
        }*/
    }

    private fun initFullScreen() {
        if (!isPad(this)) {
            requestWindowFeature(Window.FEATURE_NO_TITLE)
            window.setFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN
            )
        }
    }

    //pad和手机布局不同所以写sw600dp
    open fun getContentResId() = R.layout.bjy_activity_live_room_pad


    private fun switchRoomLayout() {
        findViewById<View>(R.id.activity_live_room_pad_room_main_video_container).visibility =
            if (routerViewModel.isLiveWall()) View.GONE else View.VISIBLE
    }

    private var enterCount = 0//记录进入教室次数，临时排查问题增加

    //TODO: onCrate之后做相关直播间初始化进入操作
    /**
     * 进入教室或者重连 首次进入会进行直播间加入操作
     */
    private fun enterRoom(liveRoom: LiveRoom? = null) {
        routerViewModel = getViewModel { RouterViewModel() }
        liveRoomViewModel = getViewModel { LiveRoomViewModel(routerViewModel) }
        oldBridge = OldLiveRoomRouterListenerBridge(routerViewModel)
        enterCount++
        onLoadingCompleteListener = object : OnLoadingCompleteListener {
            fun navigateToMain() {
                routerViewModel.actionNavigateToMain.value = true
            }

            override fun onLoadingSteps(step: Int, totalSteps: Int) {
                if (step == 2) {
                    ThemeDataUtil.initThemeConfig(routerViewModel.liveRoom.customColor)
                    routerViewModel.action2UpdateTheme.value = Unit
                    val hideBJYSupportMessage =
                        routerViewModel.liveRoom.partnerConfig?.hideBJYSupportMessage
                            ?: 1
                    routerViewModel.shouldShowTecSupport.value = hideBJYSupportMessage == 0
                }
            }

            @RequiresApi(Build.VERSION_CODES.M)
            override fun onLoadingComplete(liveRoom: LiveRoom) {
                liveRoom.also {
                    if (liveRoom.isUseWebRTC) {
                        //webrtc推流前必须要有视频权限
                        if (liveRoom.isTeacherOrAssistant) {
                            if (checkTeacherCameraPermission()) {
                                navigateToMain()
                            }
                        } else {
                            if (liveRoom.roomType != LPConstants.LPRoomType.Multi) {
                                if (checkTeacherCameraPermission()) {
                                    navigateToMain()
                                }
                            } else {
                                navigateToMain()
                            }
                        }
                    } else {
                        navigateToMain()
                    }
                }
            }

            override fun onLoadingError(error: LPError?) {
                routerViewModel.actionShowError.value = error
            }
        }
        //页面相关动作状态订阅
        observeActions()
        if (loadingWindow == null) {
            loadingWindow = LoadingWindow(this@LiveRoomTripleActivity, false)
        }
        loadingContainer.removeAllViews()
        loadingContainer.addView(loadingWindow?.view)
        if (liveRoom == null) {
            loadingWindow?.checkDevice(object : LoadingWindow.EnterRoomListener {
                /**
                 * 设备状态检测正常 点击进入会回调到此处
                 */
                override fun onEnterRoom() {
                    loadingContainer.visibility = View.VISIBLE
                    if (joinCodeEnterRoomModel != null) {
                        //开始做邀请码进入直播间
                        routerViewModel.liveRoom = loadingWindow!!.enterRoom(
                                joinCodeEnterRoomModel,
                                onLoadingCompleteListener as OnLoadingCompleteListener
                        )
                    } else {
                        //ID方式加入直播间进入直播间
                        routerViewModel.liveRoom = loadingWindow!!.enterRoom(
                                signEnterRoomModel,
                                onLoadingCompleteListener as OnLoadingCompleteListener
                        )
                    }
                    routerViewModel.isReConnect = false
                }
            })
        } else {
            routerViewModel.liveRoom = liveRoom
            loadingWindow!!.reconnect(
                    liveRoom,
                    onLoadingCompleteListener as OnLoadingCompleteListener
            )
            routerViewModel.isReConnect = true
        }
    }

    //TODO:订阅相关动作
    /**
     * 订阅相关都动作处理
     */
    private fun observeActions() = with(routerViewModel) {
        //变换主题订阅
        action2UpdateTheme.observe(this@LiveRoomTripleActivity, Observer {
            skinInflateFactory.updateTheme(ThemeDataUtil.getThemeConfig())
            val rootContainer = findViewById<View>(R.id.activity_live_room_root_container)
            if (rootContainer != null) {
                rootContainer.setBackgroundColor(
                    ThemeDataUtil.getColorFromThemeConfigByAttrId(
                        this@LiveRoomTripleActivity,
                        R.attr.base_theme_room_bg_color
                    )
                )
            } else {
                findViewById<View>(R.id.activity_live_room_pad_background)?.setBackgroundColor(
                    ThemeDataUtil.getColorFromThemeConfigByAttrId(
                        this@LiveRoomTripleActivity,
                        R.attr.base_theme_room_bg_color
                    )
                )
            }
            initView()
            initLiveRoom()
        })

        //退出点击动作订阅 TopMenuFragment点击退出 回调到此处
        actionExit.observe(this@LiveRoomTripleActivity, Observer {
            it?.let { showExitDialog() }
        })

        //在LoadingWindow.enterRoom => LiveSDK.enterRoom（进入直播间SDK方法） 成功之后如果完成则对对应处理
        actionNavigateToMain.observeForever(navigateToMainObserver)

        speakListCount.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                this@LiveRoomTripleActivity.findViewById<View>(R.id.activity_live_room_pad_room_videos_container)?.visibility =
                    if (it == 0) View.GONE else View.VISIBLE
                //不显示座位席&显示了标题栏，主屏公告主动下移一个标题栏高度，避免遮挡
                (mainScreenNoticeContainer?.layoutParams as? FrameLayout.LayoutParams)?.topMargin =
                    if (it == 0 && this@LiveRoomTripleActivity.findViewById<View>(R.id.activity_live_room_pad_room_top_parent)?.visibility == View.VISIBLE)
                        resources.getDimension(R.dimen.top_menu_height).toInt() else 0
            }
        })

        //错误处理检测 在LoadingWindow.enterRoom => LiveSDK.enterRoom（进入直播间SDK方法）
        //会通过回调如果错误，则动态修改actionShowError的值 对弹出框操作 调用ErrorPadFragment
        actionShowError.observeForever(showErrorObserver)

        //ErrorPadFragment 调用  retry()
        actionDismissError.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                errorContainer.visibility = View.GONE
            }
        })

        actionReEnterRoom.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                doReEnterRoom(it.first, it.second)
            }
        })
        isShowEyeCare.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                findViewById<View>(R.id.activity_class_eye_care_layer).visibility =
                    if (it) View.VISIBLE else View.GONE
            }
        })
        action2Setting.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                if(settingFragment == null) {
                    settingFragment = SettingDialogFragment.newInstance()
                }
                showDialogFragment(settingFragment)
            }
        })
        action2Share.observe(this@LiveRoomTripleActivity, Observer {
            it?.let { navigateToShare() }
        })
        actionShowQuickSwitchPPT.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                val quickSwitchPPTFragment = QuickSwitchPPTFragment.newInstance(it)
                quickSwitchPPTPresenter = SwitchPPTFragmentPresenter(quickSwitchPPTFragment, true)
                quickSwitchPPTPresenter?.run {
                    bindVP(quickSwitchPPTFragment, this)
                    showDialogFragment(quickSwitchPPTFragment)
                }
            }
        })
        actionChangePPT2Page.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                quickSwitchPPTPresenter?.notifyMaxIndexChange(it)
            }
        })
        actionShowPPTManager.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                handlePPTManageWindow(it)
            }
        })
        actionShowSendMessageFragment.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                if (messageSentFragment.isAdded) return@Observer
                messageSendPresenter = MessageSendPresenter(messageSentFragment)
                messageSendPresenter?.setView(messageSentFragment)
                bindVP(messageSentFragment, messageSendPresenter!!)
                if (routerViewModel.choosePrivateChatUser) {
                    messageSentFragment.setAutoChoosePrivateChatUser(true)
                    routerViewModel.choosePrivateChatUser = false
                }
                messageSentFragment.setEnterMessage(it)
                showDialogFragment(messageSentFragment)
            }
        })
        actionShowAnnouncementFragment.observe(this@LiveRoomTripleActivity, Observer {
            if (it == true) {
                navigateToAnnouncement()
            }
        })
        actionShowQAInteractiveFragment.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                navigateToQAInteractive()
            }
        })
        shouldShowTecSupport.observe(this@LiveRoomTripleActivity, Observer {
            if (it != null) {
                shouldShowTechSupport = it
            }
        })
        privateChatUser.observe(this@LiveRoomTripleActivity, Observer {
            messageSendPresenter?.onPrivateChatUserChange()
        })
        actionChooseFiles.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                if (checkWriteFilePermission()) {
                    openSystemFiles(it)
                }
            }
        })
        action2Lottery.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                lotteryAnimFragment = LotteryAnimFragment()
                replaceFragment(R.id.activity_live_room_lottery_pad, lotteryAnimFragment)
                lotteryAnimFragment?.setAnimListener(object : LotteryAnimFragment.AnimListener {
                    override fun onAnimDismiss() {
                        showLotteryInfo(it)
                        removeFragment(lotteryAnimFragment)
                    }
                })
            }
        })
        actionDismissLottery.observe(this@LiveRoomTripleActivity, Observer {
            it?.let {
                removeFragment(lotteryFragment)
            }
        })
        classEnd.observeForever(classEndObserver)

        actionRoomLayoutSwitch.observeForever(roomLayoutSwitchObserver)

        action2ShowMainScreenNotice.observe(this@LiveRoomTripleActivity, Observer {
            LPRxUtils.dispose(disposeOfMainScreenNotice)
            mainScreenNoticeAnimator?.cancel()
            if (it.isEmpty()) {
                return@Observer
            }
            mainScreenNoticeContainer = FrameLayout(this@LiveRoomTripleActivity)
            val bgDrawable = ColorDrawable(Color.parseColor(it[0].bgColor))
            val interval = it[0].rollInterval
            bgDrawable.alpha = ((it[0].bgTransparency / 100f) * 255).roundToInt()
            mainScreenNoticeContainer?.background = bgDrawable
            var index = 0
            disposeOfMainScreenNotice = Observable.interval(0, interval.toLong(), TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { it2 ->
                    if (mainScreenNoticeAnimator?.isRunning == true) {
                        return@subscribe
                    }
                    val mainScreenNoticeModel = it[index % it.size]
                    val noticeTextView = TextView(this@LiveRoomTripleActivity)
                    noticeTextView.run {
                        text = mainScreenNoticeModel.content
                        textSize = mainScreenNoticeModel.fontSize
                        alpha = mainScreenNoticeModel.fontTransparency / 100f
                        setTextColor(Color.parseColor(mainScreenNoticeModel.fontColor))
                        if (mainScreenNoticeModel.link.startsWith("http")) {
                            setOnClickListener {
                                val intent = Intent(Intent.ACTION_VIEW)
                                intent.data = Uri.parse(mainScreenNoticeModel.link)
                                startActivity(intent)
                            }
                        }
                    }
                    val noticeTextViewSize = DisplayUtils.getUnDisplayViewSize(noticeTextView)
                    val layoutParams = FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.WRAP_CONTENT,
                        FrameLayout.LayoutParams.WRAP_CONTENT
                    )
                    layoutParams.run {
                        gravity = Gravity.END
                        marginEnd = -noticeTextViewSize[0]
                        topMargin = DisplayUtils.dip2px(this@LiveRoomTripleActivity, 4f)
                        bottomMargin = topMargin
                    }
                    mainScreenNoticeContainer?.addView(noticeTextView, layoutParams)
                    val noticeContainerLayoutParams = FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.WRAP_CONTENT
                    )
                    //显示标题&没显示发言列表，设置topMargin避免主屏公告被遮挡
                    if (this@LiveRoomTripleActivity.findViewById<View>(R.id.activity_live_room_pad_room_top_parent)?.visibility == View.VISIBLE &&
                        this@LiveRoomTripleActivity.findViewById<View>(R.id.activity_live_room_pad_room_videos_container)?.visibility == View.GONE
                    ) {
                        noticeContainerLayoutParams.topMargin =
                            resources.getDimension(R.dimen.top_menu_height).toInt()
                    }
                    pptContainer.addView(mainScreenNoticeContainer, noticeContainerLayoutParams)
                    mainScreenNoticeAnimator = ObjectAnimator.ofFloat(
                        noticeTextView,
                        "translationX",
                        -pptContainer.width.toFloat() - noticeTextViewSize[0]
                    )
                    mainScreenNoticeAnimator?.run {
                        duration =
                            ((pptContainer.width + noticeTextViewSize[0]) / 100f * 1000).toLong()
                        interpolator = LinearInterpolator()
                        addListener(object : AnimatorListenerAdapter() {
                            override fun onAnimationEnd(animation: Animator) {
                                mainScreenNoticeContainer?.removeAllViews()
                                pptContainer.removeView(mainScreenNoticeContainer)
                            }
                        })
                        start()
                    }
                    index++
                }
        })
        startScreenShare.observe(this@LiveRoomTripleActivity, Observer {
            if (screenShareHelper == null) {
                screenShareHelper = ScreenShareHelper(this@LiveRoomTripleActivity, liveRoom)
                screenShareHelper?.screenShareListener = object : ScreenShareHelper.ScreenShareListener {
                    override fun onScreenShareState(state: LPConstants.LPScreenShareState) {
                        if (state == LPConstants.LPScreenShareState.START) {
                            if (liveRoom.speakQueueVM.isPresenterUser(liveRoom.currentUser)) {
                                liveRoom.requestPPTVideoSwitch(true)
                            }
                        } else if (state == LPConstants.LPScreenShareState.STOP || state == LPConstants.LPScreenShareState.ERROR) {
                            if (liveRoom.speakQueueVM.isPresenterUser(liveRoom.currentUser)) {
                                liveRoom.requestPPTVideoSwitch(false)
                            }
                            if (!CommonUtils.isAppForeground(this@LiveRoomTripleActivity)) {
                                routerViewModel.screenShareEndBackstage.value = Unit
                            }
                        }
                    }

                    override fun onScreenShareStop() {
                        val dialog = ThemeMaterialDialogBuilder(this@LiveRoomTripleActivity)
                            .title(R.string.bjy_base_screen_share_stop_title)
                            .positiveText(R.string.base_confirm)
                            .negativeText(R.string.base_cancel)
                            .onPositive { materialDialog, _ ->
                                run {
                                    screenShareHelper?.stopScreenCapture()
                                    materialDialog.dismiss()
                                }
                            }
                            .onNegative { materialDialog, _ -> materialDialog.dismiss() }
                            .build()
                        dialog.window?.setDimAmount(1.0f)
                        dialog.show()
                    }
                }
            }
            if (!liveRoom.getRecorder<LPRecorder>().isVideoAttached) {
                routerViewModel.actionAttachLocalVideo.value = true
            }
            screenShareHelper?.startScreenCapture()
        })
    }


    open fun initView() {
        //PPTView相关
        pptContainer.id = View.generateViewId()
        removeViewFromParent(pptContainer)
        toolboxLayer = findViewById(R.id.activity_live_toolbox)
        pptContainerViewGroup = findViewById(R.id.activity_live_room_pad_room_ppt_container)
        pptContainerViewGroup?.addView(
                pptContainer,
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT
        )
        //设置主视频、PPT、右侧聊天、说话Fragment
        supportFragmentManager.beginTransaction()
                .replace(
                        R.id.activity_live_room_pad_room_main_video_container,
                        MainVideoFragment.newInstance()
                )
                .replace(
                        R.id.activity_live_room_pad_room_interaction_container,
                        InteractiveFragment.newInstance()
                )
                .replace(pptContainer.id, PPTFragment.newInstance())
                .replace(R.id.activity_live_room_pad_room_videos_container, SpeakFragment.newInstance())
                .commitNowAllowingStateLoss()
        routerViewModel.isShowEyeCare.value =
                findViewById<View>(R.id.activity_class_eye_care_layer).visibility == View.VISIBLE
        findViewById<View>(R.id.btnPrtLand).setOnClickListener {
            if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
            }else{
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
            }

        }
    }

    //中奖信息
    private fun showLotteryInfo(lpLotteryResultModel: LPLotteryResultModel) {
        lotteryFragment = LotteryFragment()
        lotteryFragment?.setResultModel(lpLotteryResultModel)
        replaceFragment(R.id.activity_live_room_lottery_anim_pad, lotteryFragment)
    }

    private fun openSystemFiles(uploadType: BaseUIConstant.UploadType?) {
        val intent = Intent(Intent.ACTION_GET_CONTENT)
        // reference : https://en.wikipedia.org/wiki/Media_type
        intent.type = "*/*"
        intent.addCategory(Intent.CATEGORY_OPENABLE)
        try {
            startActivityForResult(intent, uploadType!!.value)
        } catch (e: ActivityNotFoundException) {
            showToastMessage("亲，木有文件管理器啊-_-!!")
        }
    }

    private fun checkWriteFilePermission(): Boolean {
        if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
        ) {
            return true
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                REQUEST_CODE_PERMISSION_WRITE
            )
        }
        return false
    }

    private fun initLiveRoom() {
        LPSdkVersionUtils.setSdkVersion(LPSdkVersionUtils.MULTI_CLASS_UI + BuildConfig.BJY_SDK_VERSION_NAME)
        routerViewModel.liveRoom.setOnLiveRoomListener { error ->
            when (error.code.toInt()) {
                LPError.CODE_ERROR_ROOMSERVER_LOSE_CONNECTION,
                LPError.CODE_ERROR_WEBRTC_SERVER_DISCONNECTED -> routerViewModel.actionReEnterRoom.value =
                    LiveSDK.checkTeacherUnique to false
                LPError.CODE_ERROR_NETWORK_FAILURE -> {
                    loadingContainer.removeView(loadingWindow?.view)
                    if (errorFragment.isAdded || findFragment(loadingContainer.id) is ErrorPadFragment) return@setOnLiveRoomListener
                    showErrorDlg(error)
                }
                LPError.CODE_ERROR_NETWORK_MOBILE -> {
                    if (!mobileNetworkDialogShown && isForeground) {
                        mobileNetworkDialogShown = true
                        try {
                            if (isFinishing) return@setOnLiveRoomListener
                            ThemeMaterialDialogBuilder(this)
                                .content(getString(R.string.base_live_mobile_network_hint))
                                .positiveText(getString(R.string.base_live_mobile_network_confirm))
                                .onPositive { materialDialog, _ -> materialDialog.dismiss() }
                                .canceledOnTouchOutside(true)
                                .build()
                                .show()
                        } catch (e: WindowManager.BadTokenException) {
                            e.printStackTrace()
                        }
                    } else {
                        showMessage(getString(R.string.base_live_mobile_network_hint_less))
                    }
                }
                LPError.CODE_ERROR_LOGIN_CONFLICT -> {
                }
                LPError.CODE_ERROR_OPEN_AUDIO_RECORD_FAILED -> {
                    if (!TextUtils.isEmpty(error.message)) {
                        showMessage(error.message)
                    }
                }
                LPError.CODE_ERROR_OPEN_AUDIO_CAMERA_FAILED -> {
                    if (!TextUtils.isEmpty(error.message)) {
                        showMessage(error.message)
                    }
                    oldBridge.detachLocalVideo()
                }
                LPError.CODE_WARNING_PLAYER_LAG, LPError.CODE_WARNING_PLAYER_MEDIA_SUBSCRIBE_TIME_OUT,
                LPError.CODE_ERROR_MEDIA_PLAY_FAILED -> {
                }
                else -> if (!TextUtils.isEmpty(error.message)) {
                    showMessage(error.message)
                }
            }
        }

        disposables.add(
            routerViewModel.liveRoom.observableOfRoomReload
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { lpResRoomReloadModel: LPResRoomReloadModel ->
                    if (lpResRoomReloadModel.eventType == "webrtc_type_change") {
                        ToastCompat.showToast(LiveRoomTripleActivity@ this, getString(R.string.switch_webrtc_type), Toast.LENGTH_SHORT)
                        doReEnterRoom(true, true)
                    }
                }
        )

        disposables.add(
            routerViewModel.liveRoom.observableOfWebrtcChange
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    ToastCompat.showToast(LiveRoomTripleActivity@ this, getString(R.string.switch_webrtc_type), Toast.LENGTH_SHORT)
                    doReEnterRoom(true, true)
                }
        )
    }

    /**
     * 重进房间或者重连
     * reEnterRoom： true重进(php、ms、rs) false重连（liveRoom复用，只连ms、rs）
     */
    private fun doReEnterRoom(checkTeacherUnique: Boolean, reEnterRoom: Boolean = false) {
        LiveSDK.checkTeacherUnique = checkTeacherUnique
        if (reEnterRoom) {
            release(true)
            enterRoom()
        } else {
            val liveRoom = routerViewModel.liveRoom
            release()
            enterRoom(liveRoom)
        }
    }

    /**
     * 订阅成功
     */
    private fun observeSuccess() {
        liveRoomViewModel.run {
            extraMediaChange.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    if (it.first == LPConstants.MediaSourceType.ExtCamera) {
                        if (it.second) {
                            showMessage(getString(R.string.lp_override_role_teacher) + "打开了辅助摄像头")
                        } else {
                            showMessage(getString(R.string.lp_override_role_teacher) + "关闭了辅助摄像头")
                        }
                    } else {
                        if (it.second) {
                            showMessage(getString(R.string.lp_override_role_teacher) + "打开了屏幕分享")
                        } else {
                            showMessage(getString(R.string.lp_override_role_teacher) + "关闭了屏幕分享")
                        }
                    }
                }
            })
            mediaStatus.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    when (it) {
                        LiveRoomViewModel.MediaStatus.VIDEO_AUDIO_ON -> showMessage(getString(R.string.lp_override_role_teacher) + "打开了麦克风和摄像头")
                        LiveRoomViewModel.MediaStatus.VIDEO_ON -> showMessage(getString(R.string.lp_override_role_teacher) + "打开了摄像头")
                        LiveRoomViewModel.MediaStatus.AUDIO_ON -> showMessage(getString(R.string.lp_override_role_teacher) + "打开了麦克风")
                        LiveRoomViewModel.MediaStatus.VIDEO_AUDIO_CLOSE -> showMessage(getString(R.string.lp_override_role_teacher) + "关闭了麦克风和摄像头")
                        LiveRoomViewModel.MediaStatus.VIDEO_CLOSE -> showMessage(getString(R.string.lp_override_role_teacher) + "关闭了摄像头")
                        LiveRoomViewModel.MediaStatus.AUDIO_CLOSE -> showMessage(getString(R.string.lp_override_role_teacher) + "关闭了麦克风")
                    }
                }
            })
            forbidChatAllModel.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    showMessageForbidAllChat(it)
                }
            })
            classSwitch.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    showClassSwitch()
                }
            })
            showToast.observeForever(toastObserver)
            reportAttention.observeForever(reportObserver)
        }
        routerViewModel.run {
            showTeacherIn.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    if (it) {
                        showMessage(
                            getString(R.string.lp_override_role_teacher) + "进入了" + getString(
                                R.string.lp_override_classroom
                            )
                        )
                    } else {
                        showMessage(
                            getString(R.string.lp_override_role_teacher) + "离开了" + getString(
                                R.string.lp_override_classroom
                            )
                        )
                    }
                }
            })
            action2RedPacketUI.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    if (it.first) {
                        showRedPacketUI(it.second)
                    } else {
                        dismissRedPacketUI()
                    }
                }
            })
            showEvaDlg.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    if (it) showEvaluation() else dismissEvaDialog()
                }
            })
            quizStatus.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    when (it.first) {
                        RouterViewModel.QuizStatus.START -> {
                            onQuizStartArrived(it.second)
                        }
                        RouterViewModel.QuizStatus.RES -> {
                            onQuizRes(it.second)
                        }
                        RouterViewModel.QuizStatus.END -> {
                            onQuizEndArrived(it.second)
                        }
                        RouterViewModel.QuizStatus.SOLUTION -> {
                            onQuizSolutionArrived(it.second)
                        }
                        RouterViewModel.QuizStatus.CLOSE -> dismissQuizDlg()
                        RouterViewModel.QuizStatus.NOT_INIT -> {
                        }
                    }
                }
            })
            answerStart.observeForever(answerObserver)
            answerEnd.observeForever(answerEndObserver)
            redPacketPublish.observeForever { showRedPacketPublish() }

            showRollCall.observeForever(showRollCallObserver)
            dismissRollCall.observeForever(dismissRollCallObserver)
            actionRollCallResult.observeForever(rollCallResultObserver)

            showResponder.observeForever(showResponderObserver)
            responderStart.observeForever(startResponderObserver)
            responderEnd.observeForever(endResponderObserver)

            showTimer.observeForever(timerObserver)
            showTimerShowy.observe(this@LiveRoomTripleActivity, Observer {
                it?.let { if (it.first) showTimerShowy(it.second) }
            })
            action2Award.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    showAwardAnimation(it)
                }
            })
            timeOutStart.observeForever(timeOutObserver)
            speakApplyStatus.observeForever(speakStatusObserver)
            switch2FullScreen.observeForever(switch2FullScreenObserver)
            actionShowWebpage.observe(this@LiveRoomTripleActivity, Observer {
                val url = Uri.parse(it).buildUpon()
                    .appendQueryParameter("class_id", liveRoom.roomId.toString())
                    .appendQueryParameter("user_number", liveRoom.currentUser.number)
                    .appendQueryParameter("user_name", liveRoom.currentUser.name).toString()
                customWebPageDialogFragment.setRouter(oldBridge)
                if (customWebPageDialogFragment.isAdded) {
                    customWebPageDialogFragment.loadUrl(url)
                } else {
                    val bundle = Bundle()
                    var size = routerViewModel.liveRoom.partnerConfig.getLiveCustomWebpageSize()
                    var position = routerViewModel.liveRoom.partnerConfig.getLiveCustomWebpagePosition()
                    bundle.putFloat("width", size[0])
                    bundle.putFloat("height", size[1])
                    bundle.putFloat("x", position[0])
                    bundle.putFloat("y", position[1])
                    bundle.putString("url", url)
                    customWebPageDialogFragment.arguments = bundle
                    showDialogFragment(customWebPageDialogFragment)
                }
            })
            actionCloseWebpage.observe(this@LiveRoomTripleActivity, Observer {
                if (customWebPageDialogFragment.isAdded && customWebPageDialogFragment.isVisible) {
                    customWebPageDialogFragment.dismissAllowingStateLoss()
                }
            })
            actionShowToast.observe(this@LiveRoomTripleActivity, Observer {
                it?.let { showToastMessage(it) }
            })
            actionShowBonusPointsWindow.observe(this@LiveRoomTripleActivity, Observer {
                it?.let {
                    if (it) {
                        bonusPointsWindow = BonusPointsWindow(this@LiveRoomTripleActivity)
                        (bonusPointsWindow as BonusPointsWindow).closeListener =
                            View.OnClickListener {
                                routerViewModel.actionShowBonusPointsWindow.value = false
                            }
                        showWindow(
                            bonusPointsWindow,
                            resources.getDimensionPixelSize(R.dimen.bjy_base_live_bonus_points_window_width),
                            if (isAdmin(liveRoom)) {
                                resources.getDimensionPixelSize(R.dimen.bjy_base_live_bonus_points_window_height)
                            } else {
                                if (showBonusPointsTab(liveRoom)) {
                                    resources.getDimensionPixelSize(R.dimen.bjy_base_live_bonus_points_window_height_student)
                                } else {
                                    resources.getDimensionPixelSize(R.dimen.bjy_base_live_bonus_points_window_height_student_small)
                                }
                            }
                        )
                    } else {
                        destroyWindow(bonusPointsWindow)
                    }
                }
            })
        }
        afterObserveSuccess()
    }

    open fun afterObserveSuccess() {
        routerViewModel.registerSyncPPTVideo.observeForever(syncPPTVideoObserver)
    }

    private fun showAwardAnimation(pair: Pair<String, LPInteractionAwardModel>) {
        findViewById<AwardView>(R.id.award_view).run {
            startAnim()
            visibility = View.VISIBLE
            setAwardText(pair.first)
            val model = pair.second
            setAwardMedal(AwardView.TYPE_AWARD_USER, model.value.awardType)
        }
    }

    /**
     * 大小班切换 liveRoom 需保持不变
     * 其余资源清空再重新初始化
     */
    private fun showClassSwitch() {
        showMessage(getString(R.string.live_room_switch))
        val liveRoom = routerViewModel.liveRoom
        release()
        routerViewModel = getViewModel { RouterViewModel() }
        liveRoomViewModel = getViewModel { LiveRoomViewModel(routerViewModel) }
        oldBridge = OldLiveRoomRouterListenerBridge(routerViewModel)
        routerViewModel.liveRoom = liveRoom
        observeActions()
        initView()
        routerViewModel.liveRoom.switchRoom(object : LPLaunchListener {
            override fun onLaunchSteps(i: Int, i1: Int) {
                // do nothing
            }

            override fun onLaunchError(lpError: LPError) {
                routerViewModel.actionShowError.value = lpError
            }

            override fun onLaunchSuccess(liveRoom: LiveRoom) {
                routerViewModel.actionNavigateToMain.value = true
            }
        })
    }



    //TODO:enterRoom 完成 做直播间相关展示
    /**
     * 已经直播间加入成功  用户刚刚进入直播间 开始做进入页面操作
     */
    private fun navigateToMain() {
        routerViewModel.checkUnique = true
        routerViewModel.enterRoomSuccess = true
        liveRoomViewModel.counter = 0
        liveRoomViewModel.subscribe()
        routerViewModel.isClassStarted.value = routerViewModel.liveRoom.isClassStarted

        //声音操作
        val audioManager = getSystemService(Context.AUDIO_SERVICE)
        if (audioManager is AudioManager) {
            val currentVolume = audioManager.getStreamVolume(getStreamType())
            audioManager.setStreamVolume(getStreamType(), -1, 0)
            minVolume = audioManager.getStreamVolume(getStreamType())
            audioManager.setStreamVolume(getStreamType(), currentVolume, 0)
            val current = audioManager.getStreamVolume(getStreamType())
            if (current <= minVolume) {
                //设置静音
                routerViewModel.liveRoom.player.muteAllRemoteAudio(true)
            }
        }

        //首次进入做教师检测操作
        disposeOfTeacherAbsent =
            routerViewModel.liveRoom.speakQueueVM.observableOfActiveUsers.subscribe {
                //用户刚刚进入直播间，当前老师不在则提示老师不在线
                if (!routerViewModel.liveRoom.isTeacherOrAssistant && routerViewModel.liveRoom.teacherUser == null) {
                    showMessage(getString(R.string.live_room_teacher_absent))
                }
                LPRxUtils.dispose(disposeOfTeacherAbsent)
            }
        LPRxUtils.dispose(disposeOfLoginConflict)

        //做登录冲突检测 enterRoomConflictListener 默认值在LiveSDKWithUI.enterRoom 做设置
        disposeOfLoginConflict =
            routerViewModel.liveRoom.observableOfLoginConflict.observeOn(AndroidSchedulers.mainThread())
                .subscribe { iLoginConflictModel ->
                    //用户多段登录检测，如果其他端使用，则当前端退出直播间操作。
                    release()
                    if (enterRoomConflictListener != null) {
                        enterRoomConflictListener.onConflict(
                            this,
                            iLoginConflictModel.conflictEndType,
                            object : LiveSDKWithUI.LPRoomExitCallback {
                                override fun exit() {
                                    super@LiveRoomTripleActivity.finish()
                                }

                                override fun cancel() {
                                    super@LiveRoomTripleActivity.finish()
                                }
                            })
                    } else {
                        super@LiveRoomTripleActivity.finish()
                    }
                }

        //如果设置shareListener 值 则顶部菜单显示分享按钮 LiveSDKWithUI.setShareListener

        if (shareListener != null) {
            routerViewModel.isShowShare.value = true
            shareListener.getShareData(
                this,
                routerViewModel.liveRoom.roomId,
                routerViewModel.liveRoom.currentUser.group
            )
        } else {
            routerViewModel.isShowShare.value = false
        }

        //展示跑马灯
        if (!routerViewModel.liveRoom.isTeacherOrAssistant) {
            startMarqueeTape()
        }
        shouldShowTechSupport = false
        LiveSDK.checkTeacherUnique = false
        //隐藏loadingWidow 显示直播相关UI页面
        loadingContainer.visibility = View.GONE
        //进房间之后才显示顶栏
        supportFragmentManager
            .beginTransaction()
            .replace(R.id.activity_live_room_pad_room_top_container, TopMenuFragment.newInstance())
            .commitAllowingStateLoss()
        if (routerViewModel.liveRoom.partnerConfig.enablePreventScreenCapture == 1) {
            window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
        }
        afterNavigateToMain()
    }

    /**
     * 进入直播间后显示问答
     */
    open fun afterNavigateToMain() {
        if (!routerViewModel.liveRoom.isTeacherOrAssistant) {
            questionBeforeClass = routerViewModel.liveRoom.requestQuestionBeforeClass(LPDeviceUuidFactory(this).deviceUuid.toString())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    if (!TextUtils.isEmpty(it)) {
                        showQuestionDialog(it)
                    }
                }, {
                    // do nothing
                })
        }
    }

    /**
     * 显示问答Fragment
     *
     */
    private fun showQuestionDialog(url: String) {
        val dialogFragment = QuestionDialogFragment.newInstance(url)
        dialogFragment.setOnSubmitQuestionListener {
            if (it) {
                dialogFragment.dismissAllowingStateLoss()
            } else {
                finish()
            }
        }
        dialogFragment.show(supportFragmentManager, QuestionDialogFragment::class.java.name)
    }


    private fun navigateToShare() {
        if (shareListener == null || shareListener.setShareList() == null) {
            return
        }
        val shareDialog = LPShareDialog.newInstance(shareListener.setShareList())
        shareDialog.setListener { type -> shareListener.onShareClicked(this, type) }
        showDialogFragment(shareDialog)
    }

    private fun showMessageForbidAllChat(result: LPRoomForbidChatResult) {
        if (isAdmin(liveRoom = routerViewModel.liveRoom) && result.type == LPConstants.LPForbidChatType.TYPE_ALL) {
            val message = if (result.isForbid) {
                getString(R.string.string_live_uisdk_forbid_all_true)
            } else {
                getString(R.string.string_live_uisdk_forbid_all_false)
            }
            showMessage(message)
        }
    }

    private fun showRedPacketUI(lpRedPacketModel: LPRedPacketModel?) {
        if (redPacketFragment != null) {
            if (redPacketPresenter?.isRobRedPacket == true) {
                return
            }
            removeFragment(redPacketFragment)
            redPacketPresenter?.unSubscribe()
            redPacketPresenter = null
        }
        redPacketFragment = RedPacketFragment.newInstance(lpRedPacketModel)
        redPacketPresenter = RedPacketPresenter(redPacketFragment, lpRedPacketModel)
        bindVP(redPacketFragment!!, redPacketPresenter!!)
        addFragment(R.id.activity_live_room_red_packet_pad, redPacketFragment)
    }

    private fun dismissRedPacketUI() {
        if (redPacketFragment != null) {
            removeFragment(redPacketFragment)
            redPacketFragment = null
            redPacketPresenter?.unSubscribe()
            redPacketPresenter = null
        }
    }

    private fun handlePPTManageWindow(open: Boolean) {
        if (pptManageWindow == null) {
            pptManageWindow = PPTManageWindow()
        }
        if (open) {
            if (!pptManageWindow!!.isAdded) {
                addFragment(R.id.activity_live_room_ppt_manage, pptManageWindow)
            }
            if (pptManageWindow!!.isHidden) {
                showFragment(pptManageWindow)
            }
        } else {
            hideFragment(pptManageWindow)
        }
    }

    //显示公告
    private fun navigateToAnnouncement() {
        if (announcementFragment?.isAdded == true) return
        announcementFragment = AnnouncementFragment.newInstance()
        val presenter = AnnouncementPresenter(announcementFragment)
        bindVP(announcementFragment!!, presenter)
        showDialogFragment(announcementFragment)
    }

    //显示问答
    private fun navigateToQAInteractive() {
        if (qaInteractiveFragment?.isAdded == true) return
        qaInteractiveFragment = QAInteractiveFragment()
        qaInteractiveFragment?.setViewMode(routerViewModel)
        showDialogFragment(qaInteractiveFragment)
    }

    private fun showRollCallDlg(time: Int, rollCallListener: OnPhoneRollCallListener.RollCall?) {
        rollCallDialogFragment = RollCallDialogFragment()
        rollCallDialogFragment?.isCancelable = false
        rollCallDialogPresenter = RollCallDialogPresenter(rollCallDialogFragment)
        rollCallDialogPresenter?.setRollCallInfo(time, rollCallListener)
        rollCallDialogPresenter!!.setRouter(this)
        rollCallDialogFragment!!.setPresenter(rollCallDialogPresenter)
        showDialogFragment(rollCallDialogFragment)
    }

    private fun dismissRollCallDlg() {
        rollCallDialogPresenter?.timeOut()
        if (tempDialogFragment is RollCallDialogFragment) {
            tempDialogFragment = null
        }
        removeFragment(rollCallDialogFragment)
    }

    private var rollcallCdTimer: Disposable? = null
    private var questionBeforeClass: Disposable? = null
    private var lpRoomRollCallResultModel: LPRoomRollCallResultModel? = null
    private var rollCallTime = 0
    private val ROLL_CALL_CD_TIME = 60

    private fun startRollCallTimer(isRollCallStatusGoing: Boolean = false) {
        LPRxUtils.dispose(rollcallCdTimer)
        rollcallCdTimer = Observable.interval(1, TimeUnit.SECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                //点名计时器
                rollCallTime--
                if (rollCallTime == 0) {
                    LPRxUtils.dispose(rollcallCdTimer)
                    if (!isRollCallStatusGoing) {
                        //点名cd完成 —> 结束状态
                        routerViewModel.rollCallStatus = RollCallStatus.End
                        adminRollCallDlg?.setRollCallCountDown(rollCallTime, isRollCallStatusGoing)
                    }
                    //倒计时结束会收到点名结果回调，这里状态不需要本地处理
                } else {
                    adminRollCallDlg?.setRollCallCountDown(rollCallTime, isRollCallStatusGoing)
                }
            }
    }

    private fun showAdminRollCallDlg(
        duration: Int = 0,
        lpRoomRollCallResultModel: LPRoomRollCallResultModel? = null
    ) {
        if (adminRollCallDlg == null) {
            adminRollCallDlg = AdminRollCallDialogFragment()
            adminRollCallDlg?.setRouterListener(this)
            adminRollCallDlg?.lpRoomRollCallResultModel = lpRoomRollCallResultModel
            adminRollCallDlg?.duration = duration
            showDialogFragment(adminRollCallDlg)
        } else {
            adminRollCallDlg?.lpRoomRollCallResultModel = lpRoomRollCallResultModel
            adminRollCallDlg?.duration = duration
            adminRollCallDlg?.showRollCallState(routerViewModel.rollCallStatus, rollCallTime)
        }
    }

    private fun dismissAdminRollCallDlg() {
        if (adminRollCallDlg != null) {
            removeFragment(adminRollCallDlg)
            adminRollCallDlg = null
        }
    }


    private var responderIntervalDisposable: Disposable? = null
    private var responderButtonDisposable: Disposable? = null
    private var responderButtonClickDisposable: Disposable? = null
    private var responderButtonDelayDisposable: Disposable? = null

    private fun showResponderWindow() {
        if (responderWindow == null) {
            responderWindow = ResponderWindow(this)
            showWindow(
                responderWindow,
                DisplayUtils.dip2px(this, 400f),
                DisplayUtils.dip2px(this, 220f)
            )
        }
    }

    private fun showResponderPrepare(prepareTime: Int) {
        if (responderPrepareView == null) {
            responderPrepareView = LayoutInflater.from(this)
                .inflate(R.layout.uibase_layout_responder_student_prepare_tip, null)
        }
        if (responderPrepareView!!.parent != null) {
            toolboxLayer?.removeView(responderPrepareView)
        }
        val layoutParams = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.WRAP_CONTENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
        )
        layoutParams.gravity = Gravity.CENTER
        toolboxLayer?.addView(responderPrepareView, layoutParams)
        responderIntervalDisposable = Observable.interval(0, 1, TimeUnit.SECONDS)
            .take((prepareTime + 1).toLong())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { aLong: Long ->
                if (aLong == prepareTime.toLong()) {
                    toolboxLayer?.removeView(responderPrepareView)
                    showResponderButton()
                }
                QueryPlus.with(responderPrepareView).id(R.id.responder_student_counting_down)
                    .text((prepareTime - aLong).toString())
            }
    }

    private fun showResponderButton() {
        if (responderRobButton == null) {
            responderRobButton = ResponderRobButton(this)
            responderRobButton?.setDefaultSize(80)
        }
        if (responderRobButton?.parent == null) {
            val _80dp = DisplayUtils.dip2px(this, 80f)
            val layoutParams = FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
            val random = Random()
            val robButtonParent: FrameLayout = toolboxLayer!!
            val leftBound = robButtonParent.width - _80dp
            val topBound = robButtonParent.width - _80dp
            if (robButtonParent.width == 0) {
                toolboxLayer?.post(Runnable {
                    layoutParams.leftMargin = if (leftBound <= 0) 0 else random.nextInt(leftBound)
                    layoutParams.topMargin = if (topBound <= 0) 0 else random.nextInt(topBound)
                    toolboxLayer?.addView(responderRobButton, layoutParams)
                })
            } else {
                layoutParams.leftMargin = if (leftBound <= 0) 0 else random.nextInt(leftBound)
                layoutParams.topMargin = if (topBound <= 0) 0 else random.nextInt(topBound)
                toolboxLayer?.addView(responderRobButton, layoutParams)
            }
        }
        responderRobButton?.changeRobButtonStatus(ResponderRobButton.RobButtonState.NORMAL)
        responderButtonClickDisposable = LPRxUtils.clicks(responderRobButton!!)
            .throttleFirst(1, TimeUnit.SECONDS)
            .subscribe {
                responderRobButton?.changeRobButtonStatus(ResponderRobButton.RobButtonState.READY_TO_SUBMIT)
                responderRobButton?.isClickable = false
                routerViewModel.liveRoom.toolBoxVM.requestAnswerRacerParticipate(routerViewModel.liveRoom.currentUser)
                LPRxUtils.dispose(responderButtonDisposable)
            }
        responderButtonDisposable = Observable.interval(2, 2, TimeUnit.SECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                if (responderRobButton == null) {
                    LPRxUtils.dispose(responderButtonDisposable)
                } else {
                    responderRobButton?.changePositionRandom(toolboxLayer)
                }
            }
    }

    private fun cancelResponder() {
        if (responderPrepareView != null && responderPrepareView!!.parent != null) {
            toolboxLayer?.removeView(responderPrepareView)
        }
        LPRxUtils.dispose(responderIntervalDisposable)
        LPRxUtils.dispose(responderButtonDisposable)
        LPRxUtils.dispose(responderButtonClickDisposable)
    }

    private fun onQuizStartArrived(jsonModel: LPJsonModel) {
        dismissQuizDlg()
        quizFragment = QuizDialogFragment()
        val args = Bundle()
        val forceJoin = if (!JsonObjectUtil.isJsonNull(jsonModel.data, "force_join")) {
            JsonObjectUtil.getAsInt(jsonModel.data, "force_join")
        } else {
            0
        }
        args.putBoolean(QuizDialogFragment.KEY_FORCE_JOIN, forceJoin == 1)
        quizFragment?.arguments = args
        quizFragment?.isCancelable = false
        quizPresenter = QuizDialogPresenter(quizFragment)
        quizFragment?.onStartArrived(jsonModel)
        bindVP(quizFragment!!, quizPresenter!!)
        showDialogFragment(quizFragment)
    }

    private fun onQuizEndArrived(jsonModel: LPJsonModel) {
        if (quizFragment == null) {
            return
        }
        quizFragment?.onEndArrived(jsonModel)
    }

    private fun onQuizSolutionArrived(jsonModel: LPJsonModel) {
        dismissQuizDlg()
        quizFragment = QuizDialogFragment()
        val args = Bundle()
        args.putBoolean(QuizDialogFragment.KEY_FORCE_JOIN, false)
        quizFragment?.arguments = args
        quizPresenter = QuizDialogPresenter(quizFragment)
        quizFragment?.onSolutionArrived(jsonModel)
        bindVP(quizFragment!!, quizPresenter!!)
        showDialogFragment(quizFragment)
    }

    private fun onQuizRes(jsonModel: LPJsonModel) {
        dismissQuizDlg()
        quizFragment = QuizDialogFragment()
        val args = Bundle()
        val forceJoin = if (!JsonObjectUtil.isJsonNull(jsonModel.data, "force_join")) {
            JsonObjectUtil.getAsInt(jsonModel.data, "force_join")
        } else {
            0
        }
        args.putBoolean(QuizDialogFragment.KEY_FORCE_JOIN, forceJoin == 1)
        quizFragment?.arguments = args
        quizFragment?.isCancelable = false
        quizPresenter = QuizDialogPresenter(quizFragment)
        quizFragment?.onQuizResArrived(jsonModel)
        bindVP(quizFragment!!, quizPresenter!!)
        showDialogFragment(quizFragment)
    }

    private fun dismissQuizDlg() {
        if (quizFragment?.isAdded == true && quizFragment?.isVisible == true) {
            quizFragment?.dismissAllowingStateLoss()
        }
    }

    private fun initTeacherAnswerer(lpAnswerModel: LPAnswerModel) {
        if (adminAnswererWindow == null) {
            adminAnswererWindow = if (TextUtils.isEmpty(lpAnswerModel.messageType)) {
                AdminAnswererWindow(this)
            } else {
                AdminAnswererWindow(this, lpAnswerModel)
            }
            showWindow(
                adminAnswererWindow,
                resources.getDimensionPixelSize(R.dimen.live_default_answer_teacher_width),
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
        }
    }

    private fun initStudentAnswerer(lpAnswerModel: LPAnswerModel) {
        if (answererWindow == null) {
            answererWindow = AnswererWindow(this, lpAnswerModel)
            showWindow(
                answererWindow,
                resources.getDimensionPixelSize(R.dimen.live_default_answer_student_width),
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
        }
    }

    private fun showRedPacketPublish() {
        if (redPacketPublishWindow == null) {
            redPacketPublishWindow = RedPacketPublishWindow(this)
            showWindow(
                redPacketPublishWindow,
                resources.getDimensionPixelSize(R.dimen.live_red_packet_publish_window_width),
                resources.getDimensionPixelSize(R.dimen.live_red_packet_publish_window_height)
            )
        }
    }

    private fun showWindow(window: BaseWindow?, windowWidth: Int, windowHeight: Int) {
        val layoutParams = FrameLayout.LayoutParams(windowWidth, windowHeight)
        //全屏下，窗口居中
        if (pptContainerViewGroup?.measuredWidth!! > layoutParams.width && routerViewModel.switch2FullScreen.value?.first != true) {
            layoutParams.gravity = Gravity.CENTER_VERTICAL
            layoutParams.leftMargin =
                (pptContainerViewGroup?.measuredWidth?.minus(layoutParams.width))?.div(2)
                    ?: 0
        } else {
            layoutParams.gravity = Gravity.CENTER
        }
        toolboxLayer?.setBackgroundColor(ContextCompat.getColor(this, R.color.base_half_black))
        toolboxLayer?.addWindow(window, layoutParams)
    }

    private fun destroyWindow(window: BaseWindow?) {
        window?.run {
            toolboxLayer?.removeWindow(this)
            toolboxLayer?.setBackgroundColor(Color.TRANSPARENT)
            onDestroy()
        }
    }


    private fun showTimer(lpbjTimerModel: LPBJTimerModel) {
        var lpbjTimerModelTemp: LPBJTimerModel = lpbjTimerModel
        if (timerShowyFragment != null && showyTimerPresenter != null) {
            lpbjTimerModelTemp = showyTimerPresenter!!.lpbjTimerModel
        }
        timerFragment = TimerFragment()
        val timerPresenter = TimerPresenter()
        timerPresenter.setRouter(oldBridge)
        timerPresenter.setTimerModel(lpbjTimerModelTemp)
        timerPresenter.setRouterViewModel(routerViewModel)
        timerPresenter.setIsSetting(true)
        timerPresenter.setView(timerFragment)
        bindVP(timerFragment!!, timerPresenter)
        showDialogFragment(timerFragment)
    }

    private fun showTimerShowy(lpbjTimerModel: LPBJTimerModel) {
        if (timerFragment != null && timerFragment?.isAdded == true) {
            removeFragment(timerFragment)
            timerFragment = null
        }
        if (timerShowyFragment != null && timerShowyFragment?.isVisible == true) {
            return
        }
        showyTimerPresenter = TimerPresenter()
        timerShowyFragment = TimerShowyFragment()
        showyTimerPresenter!!.setRouter(oldBridge)
        showyTimerPresenter!!.setRouterViewModel(routerViewModel)
        showyTimerPresenter!!.setTimerModel(lpbjTimerModel)
        showyTimerPresenter!!.setView(timerShowyFragment)
        bindVP(timerShowyFragment!!, showyTimerPresenter!!)

        val showy = findViewById<DragFrameLayout>(R.id.activity_dialog_timer_pad);
        showy.visibility = View.VISIBLE
        val layoutParams = RelativeLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
//        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP)
        layoutParams.marginStart = DisplayUtils.dip2px(this, 16f)
        layoutParams.topMargin = DisplayUtils.dip2px(this, 34f)
        showy.layoutParams = layoutParams
        showy.assignParent(findViewById(R.id.activity_live_room_pad_background))
        addFragment(R.id.activity_dialog_timer_pad, timerShowyFragment)
        showFragment(timerShowyFragment)
    }

    private fun closeTimer() {
        if (timerShowyFragment?.isAdded == true) {
            removeFragment(timerShowyFragment)
            findViewById<DragFrameLayout>(R.id.activity_dialog_timer_pad).visibility = View.GONE
            timerShowyFragment!!.onDestroy()
            timerShowyFragment = null
            routerViewModel.showTimerShowy.value = Pair(false, LPBJTimerModel())
        }
    }

    /**
     * 显示课后评价
     */
    private fun showEvaluation() {
        if (evaDialogFragment != null) {
            dismissEvaDialog()
        }
        evaDialogFragment = EvaDialogFragment()
        val evaDialogPresenter = EvaDialogPresenter(evaDialogFragment)
        val lpJsonModel = LPJsonModel()
        val data = JsonObject()
        data.addProperty("message_type", "class_end")
        lpJsonModel.data = data
        evaDialogFragment?.onClassEnd(lpJsonModel)
        bindVP(evaDialogFragment!!, evaDialogPresenter)
        showDialogFragment(evaDialogFragment)
    }

    private fun dismissEvaDialog() {
        if (evaDialogFragment?.isAdded == true && evaDialogFragment?.isVisible == true) {
            evaDialogFragment?.dismissAllowingStateLoss()
        }
    }

    private fun showMessage(message: String) {
        showToastMessage(message)
    }

    private fun <V : BaseView<P>, P : BasePresenter> bindVP(view: V, presenter: P) {
        presenter.setRouter(oldBridge)
        view.setPresenter(presenter)
    }

    private fun hideSysUIComponent() {
        supportActionBar?.hide()
    }

    private fun canStartClass(): Boolean {
        if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Teacher) {
            return true
        }
        // 小班老师、助教在大班无上下课权限
        if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Assistant
            && routerViewModel.liveRoom.adminAuth?.classStartEnd == true
            && routerViewModel.liveRoom.currentUser.group == 0
        ) {
            return true
        }
        return false
    }

    private val exitDialogForTeacher by lazy {
        ThemeMaterialDialogBuilder(this)
            .apply {
                title(getString(R.string.live_exit_hint_title))
                content(getString(R.string.live_exit_hint_content))
            }
            .apply {
                //助教伪直播&推流直播不允許下課
                if (routerViewModel.liveRoom.currentUser.type == LPConstants.LPUserType.Assistant && (routerViewModel.liveRoom.isMockLive || routerViewModel.liveRoom.isPushLive)) {
                    return@apply
                }
                positiveText(getString(R.string.live_exit_hint_end_class_and_exit))
                positiveColorRes(R.color.base_warning_color)
                onPositive { _, _ ->
                    isSelfEnd = true
                    routerViewModel.liveRoom.requestClassEnd()
                }
            }
            .apply {
                negativeText(getString(R.string.live_exit_hint_confirm))
                onNegative { _, _ -> finish() }
            }
            .apply {
                neutralText(getString(R.string.live_cancel))
                onNeutral { dialog, _ -> dialog.dismiss() }
            }
            .cancelable(false)
            .build()

    }

    private fun showGeneratePlaybackDialog(isLongTerm: Boolean) {
        ThemeMaterialDialogBuilder(this)
            .apply {
                title(getString(R.string.live_exit_hint_title))
                val content = if (isLongTerm) getString(R.string.live_playback_generate_now)
                else getString(R.string.live_playback_generate_now) + "\n" + getString(R.string.live_playback_generate_now_tip)
                content(content)
            }
            .apply {
                positiveText(getString(R.string.live_playback_generate_now_positive))
                positiveColor(
                    ThemeDataUtil.getColorFromThemeConfigByAttrId(
                        this@LiveRoomTripleActivity,
                        R.attr.base_theme_live_product_color
                    )
                )
                onPositive { _, _ ->
                    run {
                        routerViewModel.liveRoom.requestCloudRecordStartProcessing()
                        finish()
                    }
                }
            }
            .apply {
                negativeText(getString(R.string.live_playback_generate_now_negative))
                negativeColor(
                    ThemeDataUtil.getColorFromThemeConfigByAttrId(
                        this@LiveRoomTripleActivity,
                        R.attr.base_theme_dialog_negative_text_color
                    )
                )
                onNegative { dialog, _ ->
                    run {
                        dialog.dismiss()
                        finish()
                    }
                }
            }
            .cancelable(false)
            .build()
            .apply {
                if (!isShowing) {
                    show()
                }
            }
    }

    private val exitDialogForStudent by lazy {
        ThemeMaterialDialogBuilder(this)
            .apply {
                title(getString(R.string.live_exit_hint_title))
                content(getString(R.string.live_exit_hint_content))
            }
            .apply {
                positiveText(getString(R.string.live_exit_hint_confirm))
                positiveColorRes(R.color.base_warning_color)
                onPositive { _, _ -> finish() }
            }
            .apply {
                negativeText(getString(R.string.live_cancel))
                onNegative { dialog, _ -> dialog.dismiss() }
            }
            .cancelable(false)
            .build()
    }

    private fun showExitDialog() = when {
        routerViewModel.liveRoom.isClassStarted && canStartClass() ->
            exitDialogForTeacher.apply {
                if (!isShowing) {
                    show()
                }
            }
        else ->
            exitDialogForStudent.apply {
                if (!isShowing) {
                    show()
                }
            }
    }

    private fun showKickOutDlg(error: LPError) {
        routerViewModel.kickOut.value = Unit
        release()
        val builder = AlertDialog.Builder(this)
        val dialog = builder.setMessage(error.message)
            .setPositiveButton(R.string.live_quiz_dialog_confirm) { dialog1, _ ->
                dialog1.dismiss()
                this.finish()
            }.create()
        dialog.setCancelable(false)
        if (!isFinishing) {
            dialog.show()
            dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(
                ThemeDataUtil.getColorFromThemeConfigByAttrId(
                    this,
                    R.attr.base_theme_live_product_color
                )
            )
        }
    }

    private fun showAuditionEndDlg(it: LPError) {
        if (mAuditionEndDialog == null) {
            mAuditionEndDialog = SimpleTextDialog(this, it)
            mAuditionEndDialog?.setCancelable(false)
            mAuditionEndDialog?.setOnOkClickListener {
                mAuditionEndDialog?.dismiss()
                mAuditionEndDialog = null
                //跳转link
                CommonUtils.startActivityByUrl(this, it)
                this.finish()
            }
        }
        mAuditionEndDialog?.isShowing?.let {
            mAuditionEndDialog?.show()
        }
    }



    override fun finish() {
        if (exitListener != null) {
            exitListener.onRoomExit(this, object : LiveSDKWithUI.LPRoomExitCallback {
                override fun exit() {
                    if (::routerViewModel.isInitialized && routerViewModel.isLiveRoomInitialized()) {
                        tryToCloseCloudRecord()
                    }
                    super@LiveRoomTripleActivity.finish()
                }

                override fun cancel() {
                    // do nothing
                }
            })
        } else {
            super.finish()
        }
    }


    private fun tryToCloseCloudRecord() {
        routerViewModel.liveRoom.run {
            if (isQuit) {
                return@run
            }
            if (canStartClass() && isClassStarted) {
                //只要调下课就行，TopMenuViewModel监听了classEnd暂停云端录制
                requestClassEnd()
            }
        }
    }



    override fun getRouterListener(): LiveRoomRouterListener = oldBridge

    override fun onResume() {
        super.onResume()
        screenShareHelper?.onResume()
        if (::routerViewModel.isInitialized && routerViewModel.enterRoomSuccess && routerViewModel.isLiveRoomInitialized()
            && routerViewModel.speakApplyStatus.value == RightMenuContract.STUDENT_SPEAK_APPLY_SPEAKING
        ) {
            routerViewModel.liveRoom.onlineUserVM?.updateMediaState()
        }
        if (roomLifeCycleListener != null) {
            roomLifeCycleListener.onResume(this) { _, _ ->
                doReEnterRoom(LiveSDK.checkTeacherUnique, true)
            }
        }
    }

    override fun onStop() {
        super.onStop()
        screenShareHelper?.onStop()
        if (::routerViewModel.isInitialized && routerViewModel.enterRoomSuccess && routerViewModel.isLiveRoomInitialized()
            && routerViewModel.speakApplyStatus.value == RightMenuContract.STUDENT_SPEAK_APPLY_SPEAKING
        ) {
            routerViewModel.liveRoom.onlineUserVM?.updateMediaState()
        }
    }


    private fun getStreamType(): Int {
        //ijk拉流时音量按键事件响应为媒体音量
        return if (LiveSDK.getAudioOutput() == LPConstants.VoiceType.VOICE_MEDIA || LiveSDK.USE_IJK_PULL_STREAM) AudioManager.STREAM_MUSIC else AudioManager.STREAM_VOICE_CALL
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        return when (keyCode) {
            KeyEvent.KEYCODE_VOLUME_UP -> {
                val mAudioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
                mAudioManager.adjustStreamVolume(
                    getStreamType(), AudioManager.ADJUST_RAISE,
                    AudioManager.FLAG_PLAY_SOUND or AudioManager.FLAG_SHOW_UI
                )
                val current = mAudioManager.getStreamVolume(getStreamType())
                if (current > minVolume) {
                    try {
                        routerViewModel.liveRoom.player.muteAllRemoteAudio(false)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
                true
            }
            KeyEvent.KEYCODE_VOLUME_DOWN -> {
                val mAudioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
                mAudioManager.adjustStreamVolume(
                    getStreamType(), AudioManager.ADJUST_LOWER,
                    AudioManager.FLAG_PLAY_SOUND or AudioManager.FLAG_SHOW_UI
                )
                val current = mAudioManager.getStreamVolume(getStreamType())
                if (current <= minVolume) {
                    try {
                        routerViewModel.liveRoom.player.muteAllRemoteAudio(true)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
                true
            }
            else -> {
                super.onKeyDown(keyCode, event)
            }
        }
    }

    private fun showSystemSettingDialog(type: Int) {
        if (!isFinishing) {
            ThemeMaterialDialogBuilder(this)
                .title(getString(R.string.live_sweet_hint))
                .content(mapType2String(type))
                .positiveText(getString(R.string.live_quiz_dialog_confirm))
                .onPositive { materialDialog, _ -> materialDialog.dismiss() }
                .canceledOnTouchOutside(true)
                .build()
                .show()
        }
    }

    private fun mapType2String(type: Int): String {
        return when (type) {
            REQUEST_CODE_PERMISSION_WRITE -> getString(R.string.live_no_write_permission)
            else -> ""
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        screenShareHelper?.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {
            if (BaseUIConstant.UploadType.containsValue(requestCode)) {
                val uri = data!!.data
                try {
                    if (uri != null) {
                        val path: String? = FileUtil.getPath(this, uri)
                        if (path == null) {
                            showToastMessage(getString(R.string.live_file_not_exist))
                            return
                        }
                        val value = HashMap<BaseUIConstant.UploadType, String>()
                        val uploadType = BaseUIConstant.UploadType.valueOf(requestCode)
                        if (uploadType != null) {
                            value[uploadType] = path
                        }
                        pptManageWindow?.onUpload(value)
                    }
                } catch (e: java.lang.Exception) {
                    showToastMessage(getString(R.string.live_load_file_error))
                    e.printStackTrace()
                }
            }
        }
    }

    /**
     * 相机权限检测 无权限则申请权限
     */
    @RequiresApi(Build.VERSION_CODES.M)
    protected fun checkTeacherCameraPermission(): Boolean {
        if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            )
        ) {
            return true
        } else {
            requestPermissions(
                arrayOf(Manifest.permission.CAMERA),
                REQUEST_CODE_PERMISSION_CAMERA_TEACHER
            )
        }
        return false
    }

    /**
     * 权限申请回调
     */
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            REQUEST_CODE_PERMISSION_WRITE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                openSystemFiles(routerViewModel.actionChooseFiles.value)
            } else if (grantResults.isNotEmpty()) {
                showSystemSettingDialog(REQUEST_CODE_PERMISSION_WRITE)
            }
            REQUEST_CODE_PERMISSION_CAMERA_TEACHER -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                routerViewModel.actionNavigateToMain.value = true
            } else if (grantResults.isNotEmpty()) {
                showToastMessage(getString(R.string.live_camara_permission_refused))
                this.finish()
            }
        }
    }

    override fun getLiveRoom(): LiveRoom? {
        return if (::routerViewModel.isInitialized && routerViewModel.isLiveRoomInitialized()) {
            routerViewModel.liveRoom
        } else {
            null
        }
    }

    override fun onDismissAnswerer() {
        destroyWindow(adminAnswererWindow)
        adminAnswererWindow = null
        destroyWindow(answererWindow)
        answererWindow = null
    }

    override fun onDismissRedPacketPublish() {
        destroyWindow(redPacketPublishWindow)
        redPacketPublishWindow = null
    }

    private var answerTypes: List<String> = ArrayList()

    override fun setAnswerCustomerType(types: List<String>) {
        answerTypes = types
    }

    override fun onDismissRollCall() {
        routerViewModel.dismissRollCall.value = true
    }

    override fun setRollCallStatus(status: RollCallStatus) {
        routerViewModel.rollCallStatus = status
    }

    override fun getRollCallStatus() = routerViewModel.rollCallStatus

    override fun inviteToSpeak(user: LPUserModel) {
        val winner = routerViewModel.liveRoom.onlineUserVM.getUserByNumber(user.number)
        when {
            winner == null -> showToastMessage(R.string.base_responder_winner_out)
            routerViewModel.liveRoom.onlineUserVM.isActiveUser(winner) -> {
                val activeUserList = routerViewModel.liveRoom.speakQueueVM.speakQueueList
                for (mediaModel in activeUserList) {
                    if (TextUtils.equals(mediaModel.user.userId, winner.userId)) {
                        if (!mediaModel.isAudioOn || !mediaModel.isVideoOn) {
                            routerViewModel.liveRoom.speakQueueVM.controlRemoteSpeak(
                                winner.userId,
                                true,
                                true
                            )
                        } else {
                            showToastMessage(R.string.base_student_has_been_actived)
                        }
                        return
                    }
                }
            }
            routerViewModel.liveRoom.speakQueueVM.isSpeakersFull -> {
                showToastMessage(R.string.base_active_user_is_max)
            }
            else -> {
                routerViewModel.liveRoom.speakQueueVM.controlRemoteSpeak(winner.userId, true, true)
            }
        }
    }

    override fun getAnswerCustomerType() = answerTypes

    override fun setResponderRecord(record: List<ResponderRecordModel>) {
        routerViewModel.responderRecord = record as ArrayList<ResponderRecordModel>
    }

    override fun getResponderRecord() = routerViewModel.responderRecord



    //TODO:跑马灯相关操作
    /**
     * 开启跑马灯
     */
    private fun startMarqueeTape() {
        var horseLamp: LPEnterRoomNative.LPHorseLamp? =
                routerViewModel.liveRoom.partnerConfig.liveHorseLamp
        if (horseLamp == null) {
            horseLamp = LPEnterRoomNative.LPHorseLamp()
        }
        if (!TextUtils.isEmpty(liveHorseLamp)) {
            horseLamp.value = liveHorseLamp
        }
        if (TextUtils.isEmpty(horseLamp.value)) {
            return
        }
        if (TextUtils.isEmpty(horseLamp.color)) {
            horseLamp.color = "#000000"
        }
        if (TextUtils.isEmpty(horseLamp.backgroundColor)) {
            horseLamp.backgroundColor = "#090300"
        }
        if (horseLamp.displayMode == "roll") {
            routerViewModel.marqueeAsynchronousDisplay.observe(
                    this@LiveRoomTripleActivity,
                    marqueeObserver
            )
            showMarqueeRoll(horseLamp)
        } else {
            if (horseLamp.count == 1) {
                showMarqueeTapeBlink(horseLamp)
            } else {
                showMarqueeTapeBlinkDouble(horseLamp)
            }
        }
    }

    private fun showMarqueeRoll(horseLamp: LPEnterRoomNative.LPHorseLamp) {
        // 保证取消动画时动画已停止，不会回调end
        marqueeAnimator?.let {
            if (it.isStarted || it.isRunning) {
                return
            } else {
                it.cancel()
            }
        }
        val textView = getTextView(horseLamp, false)
        val textViewSize = DisplayUtils.getUnDisplayViewSize(textView)
        // 当textview高度改变时，由于设置了自适应文本，其width也会改变，因此需要更新位置
        val lp = textView.layoutParams as RelativeLayout.LayoutParams
        lp.rightMargin = -textViewSize[0]
        textView.layoutParams = lp
        textView.invalidate()
        val translationX = (activity_live_room_pad_background.width + textViewSize[0]).toFloat()
        marqueeAnimator = ObjectAnimator.ofFloat(textView, "translationX", -translationX)
        marqueeAnimator?.run {
            duration = (translationX * 20L).toLong()
            interpolator = LinearInterpolator()
            addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    activity_live_room_pad_background.removeView(textView)
                    if (horseLamp.count == 1) routerViewModel.marqueeAsynchronousDisplay.value =
                            true to horseLamp
                }
            })
            start()
        }
        if (horseLamp.count == 2) {
            marqueeAnimatorDouble?.let {
                if (it.isStarted || it.isRunning) {
                    return
                } else {
                    it.cancel()
                }
            }
            val textView2 = getTextView(horseLamp, true)
            marqueeAnimatorDouble = ObjectAnimator.ofFloat(textView2, "translationX", -translationX)
            CoroutineScope(Job()).launch(Dispatchers.Main) {
                delay(1000)
                marqueeAnimatorDouble?.run {
                    duration = (translationX * 20L).toLong()
                    interpolator = LinearInterpolator()
                    addListener(object : AnimatorListenerAdapter() {
                        override fun onAnimationEnd(animation: Animator) {
                            activity_live_room_pad_background.removeView(textView2)
                            routerViewModel.marqueeAsynchronousDisplay.value = true to horseLamp
                        }
                    })
                    start()
                }
            }
        }
    }

    open fun showMarqueeTapeBlink(lamp: LPEnterRoomNative.LPHorseLamp) {
        val maxHeight = activity_live_room_pad_background.height
        val maxWidth = activity_live_room_pad_background.width
        marqueeBlinkTextView = getTextView(lamp, false)
        val textViewSize = DisplayUtils.getUnDisplayViewSize(marqueeBlinkTextView)
        val lp = RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        disposeOfMarquee =
                Observable.interval(0, lamp.displayBlinkDuration.toLong(), TimeUnit.SECONDS)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            if (maxHeight - textViewSize[1] <= 0) {
                                lp.topMargin = 0
                            } else {
                                lp.topMargin = Random().nextInt(maxHeight - textViewSize[1])
                            }
                            if (maxWidth - textViewSize[0] <= 0) {
                                // 闪烁显示的长度
                                lp.leftMargin =
                                        -Random().nextInt(textViewSize[0]) / 4 * 3 + (textViewSize[0] / 4)
                            } else {
                                // 理论上说限制在容器内就不会被黑边和上下边遮掩
                                lp.leftMargin = Random().nextInt(maxWidth - textViewSize[0])
                            }
                            marqueeBlinkTextView!!.layoutParams = lp
                            marqueeBlinkTextView!!.invalidate()
                        }
    }

    open fun showMarqueeTapeBlinkDouble(lamp: LPEnterRoomNative.LPHorseLamp) {
        val maxHalfHeight = activity_live_room_pad_background.height / 2
        val maxWidth = activity_live_room_pad_background.width
        // 上泳道
        marqueeBlinkTextView = getTextView(lamp, false)
        val textViewSize = DisplayUtils.getUnDisplayViewSize(marqueeBlinkTextView)
        val lp = RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        disposeOfMarquee =
                Observable.interval(0, lamp.displayBlinkDuration.toLong(), TimeUnit.SECONDS)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            if (textViewSize[1] >= maxHalfHeight) {
                                lp.topMargin = 0
                            } else {
                                lp.topMargin = Random().nextInt(maxHalfHeight - textViewSize[1])
                            }
                            if (maxWidth - textViewSize[0] <= 0) {
                                // 当宽度大于屏幕长度时，设置随机范围为宽度，最好保证随机能展示完该跑马灯
                                lp.leftMargin =
                                        -Random().nextInt(textViewSize[0]) / 4 * 3 + (textViewSize[0] / 4)
                            } else {
                                lp.leftMargin = Random().nextInt(maxWidth - textViewSize[0])
                            }
                            marqueeBlinkTextView!!.layoutParams = lp
                            marqueeBlinkTextView!!.invalidate()
                        }
        // 下泳道
        marqueeBlinkDoubleTextView = getTextView(lamp, true)
        val lp1 = RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        disposeOfMarqueeDouble =
                Observable.interval(0, lamp.displayBlinkDuration.toLong(), TimeUnit.SECONDS)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            if (maxHalfHeight <= textViewSize[1]) {
                                lp1.topMargin = maxHalfHeight
                            } else {
                                lp1.topMargin =
                                        Random().nextInt(maxHalfHeight - textViewSize[1]) + maxHalfHeight
                            }
                            if (maxWidth <= textViewSize[0]) {
                                lp1.leftMargin =
                                        -Random().nextInt(textViewSize[0]) / 4 * 3 + (textViewSize[0] / 4)
                            } else {
                                lp1.leftMargin = Random().nextInt(maxWidth - textViewSize[0])
                            }
                            marqueeBlinkDoubleTextView!!.layoutParams = lp1
                            marqueeBlinkDoubleTextView!!.invalidate()
                        }
    }

    private fun getTextView(lamp: LPEnterRoomNative.LPHorseLamp, lastAnimator: Boolean): TextView {
        val textView = TextView(this)
        with(textView) {
            text = lamp.value
            setTextColor(
                    ColorUtils.setAlphaComponent(
                            Color.parseColor(lamp.color),
                            (lamp.opacity * 255).roundToInt()
                    )
            )
            textSize = lamp.fontSize.toFloat()
            isSingleLine = true
            setPadding(20, 10, 20, 10)
            gravity = Gravity.CENTER
            setBackgroundColor(
                    ColorUtils.setAlphaComponent(
                            Color.parseColor(lamp.backgroundColor),
                            (lamp.backgroundOpacity * 255).roundToInt()
                    )
            )
            paint.isFakeBoldText = lamp.fontBold == 1
        }
        val textViewSize = DisplayUtils.getUnDisplayViewSize(textView)
        val lp = RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        val maxHeight = activity_live_room_pad_background.height
        if (lamp.count == 1) {
            // 高度，可能最高字体大小也进入不了该判断
            if (textViewSize[1] >= maxHeight) {
                textView.height = maxHeight
                textViewSize[1] = maxHeight
                // 文字自适应
                TextViewCompat.setAutoSizeTextTypeWithDefaults(
                        textView,
                        TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM
                )
                lp.topMargin = 0;
            } else {
                lp.topMargin = Random().nextInt(maxHeight - textViewSize[1])
            }
        } else if (lastAnimator) {
            // 设置成双泳道高度限制
            val maxHalfHeight = maxHeight / 2
            if (textViewSize[1] >= maxHalfHeight) {
                textView.height = maxHalfHeight
                textViewSize[1] = maxHalfHeight
                TextViewCompat.setAutoSizeTextTypeWithDefaults(
                        textView,
                        TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM
                )
                lp.topMargin = maxHalfHeight
            } else {
                lp.topMargin = Random().nextInt(maxHalfHeight - textViewSize[1]) + maxHalfHeight
            }
        } else {
            val maxHalfHeight = maxHeight / 2
            if (textViewSize[1] >= maxHalfHeight) {
                textView.height = maxHalfHeight
                textViewSize[1] = maxHalfHeight
                TextViewCompat.setAutoSizeTextTypeWithDefaults(
                        textView,
                        TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM
                )
                lp.topMargin = 0
            } else {
                lp.topMargin = Random().nextInt(maxHalfHeight - textViewSize[1])
            }
        }
        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
        lp.rightMargin = -textViewSize[0]
        activity_live_room_pad_background.addView(textView, lp)
        return textView
    }
    //======================跑马灯相关操作===============
    //TODO:跑马灯结束

    /**
     * 显示直播错误Fragment ErrorPadFragment
     */
    private fun showErrorDlg(it: LPError?) {
        val errorCode = it?.code?.toInt()
        val errorModel = getViewModel { ErrorFragmentModel() }
        when (errorCode) {
            LPError.CODE_ERROR_LOGIN_UNIQUE_CONFLICT -> {
                routerViewModel.checkUnique = false
                errorModel.init(ErrorPadFragment.ErrorType.ERROR_HANDLE_CONFILICT)
                errorModel.checkUnique = false
            }
            LPError.CODE_ERROR_NEW_SMALL_COURSE, LPError.CODE_ERROR_MAX_STUDENT, LPError.CODE_ERROR_ENTER_ROOM_FORBIDDEN -> {
                errorModel.init(
                        ErrorPadFragment.ErrorType.ERROR_HANDLE_REENTER,
                        false,
                        getString(R.string.base_live_override_error),
                        it.message
                )
            }
            LPError.CODE_ERROR_HOST_UNKNOW -> {
                errorModel.init(
                        ErrorPadFragment.ErrorType.ERROR_HANDLE_REENTER,
                        false,
                        getString(R.string.base_live_host_unknow),
                        it.message
                )
            }
            LPError.CODE_ERROR_CLASS_END_KICK_OUT_TIPS, LPError.CODE_ERROR_CLASS_EXPIRED -> {
                errorModel.init(
                        ErrorPadFragment.ErrorType.ERROR_HANDLE_FINISH,
                        false,
                        getString(R.string.base_live_enter_deny),
                        it.message
                )
            }
            else -> errorModel.init(
                    ErrorPadFragment.ErrorType.ERROR_HANDLE_REENTER,
                    true,
                    getString(R.string.base_live_override_error),
                    it!!.message
            )
        }
        replaceFragment(errorContainer.id, errorFragment)
    }

    override fun onBackPressed() {
        if (exitListener != null) {
            super.onBackPressed()
        } else {
            if (routerViewModel.isLiveRoomInitialized()) {
                routerViewModel.actionExit.value = Unit
            } else {
                finish()
            }
        }
    }

    //页面关闭
    override fun onDestroy() {
        if (routerViewModel.isLiveRoomInitialized()) {
            routerViewModel.liveRoom.quitRoom()
        }
        screenShareHelper?.onDestroy()
        screenShareHelper = null
        routerViewModel.enterRoomSuccess = false
        removeObservers()
        super.onDestroy()
        pptManageWindow?.onDestroy()
        LPRxUtils.dispose(disposeOfTeacherAbsent)
        LPRxUtils.dispose(disposeOfLoginConflict)
        LPRxUtils.dispose(disposeOfMarquee)
        activity_live_room_pad_background.removeView(marqueeBlinkTextView)
        LPRxUtils.dispose(disposeOfMarqueeDouble)
        activity_live_room_pad_background.removeView(marqueeBlinkDoubleTextView)
        job.cancel()
        LPRxUtils.dispose(disposeOfMainScreenNotice)
        LPRxUtils.dispose(responderIntervalDisposable)
        LPRxUtils.dispose(responderButtonDisposable)
        LPRxUtils.dispose(responderButtonClickDisposable)
        LPRxUtils.dispose(responderButtonDelayDisposable)
        marqueeAnimator?.cancel()
        marqueeAnimatorDouble?.cancel()
        viewModelStore.clear()
        clearStaticCallback()
        resetAudioMode()
        ThemeDataUtil.clearConfig()
        disposables.dispose()
    }

    //重置声音模式
    private fun resetAudioMode() {
        val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
        audioManager.mode = AudioManager.MODE_NORMAL
    }


    //TODO:页面关闭释放对应资源
    /**
     * 接触RXjava 相关订阅
     */
    private fun removeObservers() {
        routerViewModel.answerStart.removeObserver(answerObserver)
        routerViewModel.answerEnd.removeObserver(answerEndObserver)
        routerViewModel.showTimer.removeObserver(timerObserver)
        routerViewModel.timeOutStart.removeObserver(timeOutObserver)
        routerViewModel.actionShowError.removeObserver(showErrorObserver)
        routerViewModel.actionNavigateToMain.removeObserver(navigateToMainObserver)
        routerViewModel.speakApplyStatus.removeObserver(speakStatusObserver)
        routerViewModel.showRollCall.removeObserver(showRollCallObserver)
        routerViewModel.dismissRollCall.removeObserver(dismissRollCallObserver)
        routerViewModel.actionRollCallResult.removeObserver(rollCallResultObserver)
        routerViewModel.showResponder.removeObserver(showResponderObserver)
        routerViewModel.responderStart.removeObserver(startResponderObserver)
        routerViewModel.responderEnd.removeObserver(endResponderObserver)
        routerViewModel.switch2FullScreen.removeObserver(switch2FullScreenObserver)
        routerViewModel.registerSyncPPTVideo.removeObserver(syncPPTVideoObserver)
        routerViewModel.classEnd.removeObserver(classEndObserver)
        routerViewModel.actionRoomLayoutSwitch.removeObserver(roomLayoutSwitchObserver)
        liveRoomViewModel.showToast.removeObserver(toastObserver)
        liveRoomViewModel.reportAttention.removeObserver(reportObserver)
        routerViewModel.marqueeAsynchronousDisplay.removeObserver(marqueeObserver)
        timeOutDisposes.forEach { (_, dispose) -> LPRxUtils.dispose(dispose) }
        LPRxUtils.dispose(rollcallCdTimer)
        LPRxUtils.dispose(questionBeforeClass)
    }

    /**
     * 释放资源
     */
    private fun release(quitRoom: Boolean = false) {
        LPRxUtils.dispose(disposeOfTeacherAbsent)
        LPRxUtils.dispose(disposeOfLoginConflict)
        LPRxUtils.dispose(disposeOfMarquee)
        activity_live_room_pad_background.removeView(marqueeBlinkTextView)
        LPRxUtils.dispose(disposeOfMarqueeDouble)
        activity_live_room_pad_background.removeView(marqueeBlinkDoubleTextView)
        LPRxUtils.dispose(disposeOfMainScreenNotice)
        LPRxUtils.dispose(responderIntervalDisposable)
        LPRxUtils.dispose(responderButtonDisposable)
        LPRxUtils.dispose(responderButtonClickDisposable)
        LPRxUtils.dispose(responderButtonDelayDisposable)
        screenShareHelper?.onDestroy()
        screenShareHelper = null
        marqueeAnimator?.cancel()
        removeAllFragment()
        destroyWindow(answererWindow)
        answererWindow = null
        destroyWindow(adminAnswererWindow)
        adminAnswererWindow = null
        destroyWindow(bonusPointsWindow)
        bonusPointsWindow = null
        destroyWindow(redPacketPublishWindow)
        redPacketPublishWindow = null
        destroyWindow(responderWindow)
        responderWindow = null
        supportFragmentManager.executePendingTransactions()
        routerViewModel.enterRoomSuccess = false
        if (quitRoom) {
            routerViewModel.liveRoom.quitRoom()
        }
        removeObservers()
        // 先解除MarqueeLivedata Observer再取消动画
        marqueeAnimator?.cancel()
        marqueeAnimatorDouble?.cancel()
        viewModelStore.clear()
    }
}
